imean-service-engine-htmx-plugin 2.5.0 → 2.7.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.d.mts +357 -116
- package/dist/index.d.ts +357 -116
- package/dist/index.js +322 -591
- package/dist/index.mjs +312 -588
- package/docs/README.md +0 -38
- package/package.json +1 -1
- package/docs/alpinejs-interactive-components.md +0 -653
- package/docs/custom-form-field-renderers.md +0 -541
- package/docs/field-editor-best-practices.md +0 -320
- package/docs/hono-html-best-practices.md +0 -509
package/dist/index.mjs
CHANGED
|
@@ -78,7 +78,6 @@ function renderActionButton(action, index) {
|
|
|
78
78
|
close,
|
|
79
79
|
submit,
|
|
80
80
|
formId,
|
|
81
|
-
onClick,
|
|
82
81
|
className = "",
|
|
83
82
|
target
|
|
84
83
|
} = action;
|
|
@@ -104,8 +103,7 @@ function renderActionButton(action, index) {
|
|
|
104
103
|
index
|
|
105
104
|
);
|
|
106
105
|
}
|
|
107
|
-
|
|
108
|
-
if (finalOnClick) {
|
|
106
|
+
if (close) {
|
|
109
107
|
const variantStyles = {
|
|
110
108
|
primary: "bg-blue-600 text-white hover:bg-blue-700",
|
|
111
109
|
secondary: "bg-gray-200 text-gray-800 hover:bg-gray-300",
|
|
@@ -123,7 +121,8 @@ function renderActionButton(action, index) {
|
|
|
123
121
|
"button",
|
|
124
122
|
{
|
|
125
123
|
type: "button",
|
|
126
|
-
|
|
124
|
+
"x-data": CLOSE_DIALOG_ALPINE_DATA,
|
|
125
|
+
"x-on:click": "closeDialog()",
|
|
127
126
|
className: `px-4 py-2 rounded transition-colors font-medium ${buttonStyle} ${className}`,
|
|
128
127
|
"data-testid": testId2,
|
|
129
128
|
...confirm && { "data-confirm": confirm },
|
|
@@ -167,15 +166,25 @@ function renderActionButton(action, index) {
|
|
|
167
166
|
function renderActionButtons(actions) {
|
|
168
167
|
return actions.map((action, index) => renderActionButton(action, index));
|
|
169
168
|
}
|
|
170
|
-
var
|
|
169
|
+
var CLOSE_DIALOG_ALPINE_DATA;
|
|
171
170
|
var init_action_button_renderer = __esm({
|
|
172
171
|
"src/utils/action-button-renderer.tsx"() {
|
|
173
172
|
init_button();
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
173
|
+
CLOSE_DIALOG_ALPINE_DATA = `{
|
|
174
|
+
closeDialog() {
|
|
175
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
176
|
+
if (backdrop) {
|
|
177
|
+
backdrop.classList.add('dialog-exit');
|
|
178
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
179
|
+
if (content) {
|
|
180
|
+
content.classList.add('dialog-content-exit');
|
|
181
|
+
}
|
|
182
|
+
setTimeout(() => {
|
|
183
|
+
backdrop.remove();
|
|
184
|
+
}, 200);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}`;
|
|
179
188
|
}
|
|
180
189
|
});
|
|
181
190
|
|
|
@@ -305,11 +314,6 @@ var init_cdn_cache = __esm({
|
|
|
305
314
|
url: "https://unpkg.com/htmx.org@latest",
|
|
306
315
|
mimeType: "application/javascript"
|
|
307
316
|
},
|
|
308
|
-
{
|
|
309
|
-
name: "hyperscript",
|
|
310
|
-
url: "https://unpkg.com/hyperscript.org@latest",
|
|
311
|
-
mimeType: "application/javascript"
|
|
312
|
-
},
|
|
313
317
|
{
|
|
314
318
|
name: "tailwindcss",
|
|
315
319
|
url: "https://cdn.tailwindcss.com",
|
|
@@ -319,16 +323,6 @@ var init_cdn_cache = __esm({
|
|
|
319
323
|
name: "alpinejs",
|
|
320
324
|
url: "https://unpkg.com/alpinejs@latest/dist/cdn.min.js",
|
|
321
325
|
mimeType: "application/javascript"
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
name: "idiomorph",
|
|
325
|
-
url: "https://unpkg.com/idiomorph@0.7.4/dist/idiomorph-ext.min.js",
|
|
326
|
-
mimeType: "application/javascript"
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
name: "sortablejs",
|
|
330
|
-
url: "https://unpkg.com/sortablejs@latest/Sortable.min.js",
|
|
331
|
-
mimeType: "application/javascript"
|
|
332
326
|
}
|
|
333
327
|
];
|
|
334
328
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -553,8 +547,9 @@ function renderFormField(field, initialData, formFieldRenderers) {
|
|
|
553
547
|
/* @__PURE__ */ jsx("div", { children: customRenderer({
|
|
554
548
|
field,
|
|
555
549
|
value: parsedValue,
|
|
556
|
-
initialData,
|
|
557
|
-
|
|
550
|
+
item: initialData || {},
|
|
551
|
+
name: field.name,
|
|
552
|
+
label: field.label
|
|
558
553
|
}) }),
|
|
559
554
|
field.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mt-1", children: field.description })
|
|
560
555
|
]
|
|
@@ -1851,7 +1846,12 @@ function renderDefaultValue(value) {
|
|
|
1851
1846
|
function renderField(field, value, item) {
|
|
1852
1847
|
let content;
|
|
1853
1848
|
if (field.render) {
|
|
1854
|
-
const rendered = field.render(
|
|
1849
|
+
const rendered = field.render({
|
|
1850
|
+
value,
|
|
1851
|
+
item,
|
|
1852
|
+
name: field.key,
|
|
1853
|
+
label: field.label
|
|
1854
|
+
});
|
|
1855
1855
|
if (rendered === null || rendered === void 0) {
|
|
1856
1856
|
content = /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "-" });
|
|
1857
1857
|
} else if (typeof rendered === "string" || typeof rendered === "number" || typeof rendered === "boolean") {
|
|
@@ -1987,11 +1987,14 @@ var DefaultDetailFeature = class extends BaseFeature {
|
|
|
1987
1987
|
const groupFields = groupSchemas.map(
|
|
1988
1988
|
({ label, schema: schema2, fields: fieldNames }) => {
|
|
1989
1989
|
const groupFields2 = parseSchemaToFields(schema2);
|
|
1990
|
-
const detailFields2 = groupFields2.map((field) =>
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1990
|
+
const detailFields2 = groupFields2.map((field) => {
|
|
1991
|
+
const renderer = this.fieldRenderers?.[field.name];
|
|
1992
|
+
return {
|
|
1993
|
+
key: field.name,
|
|
1994
|
+
label: field.label,
|
|
1995
|
+
render: renderer
|
|
1996
|
+
};
|
|
1997
|
+
});
|
|
1995
1998
|
return {
|
|
1996
1999
|
label,
|
|
1997
2000
|
fields: detailFields2,
|
|
@@ -2023,12 +2026,16 @@ var DefaultDetailFeature = class extends BaseFeature {
|
|
|
2023
2026
|
}
|
|
2024
2027
|
}
|
|
2025
2028
|
const detailFieldNames = getFieldNamesFromFields(detailFields);
|
|
2026
|
-
const fields = detailFieldNames.map((fieldName) =>
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2029
|
+
const fields = detailFieldNames.map((fieldName) => {
|
|
2030
|
+
const label = getFieldLabelFromFields(this.fields || [], fieldName) || fieldName;
|
|
2031
|
+
const renderer = this.fieldRenderers?.[fieldName];
|
|
2032
|
+
return {
|
|
2033
|
+
key: fieldName,
|
|
2034
|
+
label,
|
|
2035
|
+
// 直接使用统一的渲染器类型
|
|
2036
|
+
render: renderer
|
|
2037
|
+
};
|
|
2038
|
+
});
|
|
2032
2039
|
return /* @__PURE__ */ jsx(DetailPage, { item, fields });
|
|
2033
2040
|
}
|
|
2034
2041
|
async getActions(context) {
|
|
@@ -2807,286 +2814,6 @@ var DefaultListFeature = class extends BaseFeature {
|
|
|
2807
2814
|
}
|
|
2808
2815
|
};
|
|
2809
2816
|
|
|
2810
|
-
// src/component-system/store.ts
|
|
2811
|
-
var STATE_EXPIRATION_TIME = 864e5;
|
|
2812
|
-
var StateStore = class _StateStore {
|
|
2813
|
-
static instance;
|
|
2814
|
-
state;
|
|
2815
|
-
constructor() {
|
|
2816
|
-
this.state = /* @__PURE__ */ new Map();
|
|
2817
|
-
setInterval(() => {
|
|
2818
|
-
this.state.forEach((state) => {
|
|
2819
|
-
if (state.lastUpdated < Date.now() - STATE_EXPIRATION_TIME) {
|
|
2820
|
-
this.state.delete(state.instanceId);
|
|
2821
|
-
}
|
|
2822
|
-
});
|
|
2823
|
-
}, 3e4);
|
|
2824
|
-
}
|
|
2825
|
-
static get() {
|
|
2826
|
-
if (!_StateStore.instance) {
|
|
2827
|
-
_StateStore.instance = new _StateStore();
|
|
2828
|
-
}
|
|
2829
|
-
return _StateStore.instance;
|
|
2830
|
-
}
|
|
2831
|
-
/** 获取实例状态 */
|
|
2832
|
-
getState(instanceId) {
|
|
2833
|
-
const state = this.state.get(instanceId);
|
|
2834
|
-
if (state) {
|
|
2835
|
-
return state;
|
|
2836
|
-
}
|
|
2837
|
-
const newState = {
|
|
2838
|
-
instanceId,
|
|
2839
|
-
data: {
|
|
2840
|
-
props: {},
|
|
2841
|
-
state: {}
|
|
2842
|
-
},
|
|
2843
|
-
lastUpdated: Date.now()
|
|
2844
|
-
};
|
|
2845
|
-
this.state.set(instanceId, newState);
|
|
2846
|
-
return newState;
|
|
2847
|
-
}
|
|
2848
|
-
/** 设置实例状态 */
|
|
2849
|
-
setState(instanceId, state) {
|
|
2850
|
-
const instanceState = this.getState(instanceId);
|
|
2851
|
-
instanceState.data = Object.assign(instanceState.data.state, state);
|
|
2852
|
-
instanceState.lastUpdated = Date.now();
|
|
2853
|
-
}
|
|
2854
|
-
};
|
|
2855
|
-
|
|
2856
|
-
// src/component-system/utils.ts
|
|
2857
|
-
var globalIdCounter = 0;
|
|
2858
|
-
function generateUniqueId() {
|
|
2859
|
-
return `htmx-cid-${globalIdCounter++}`;
|
|
2860
|
-
}
|
|
2861
|
-
var HTMX_COMPONENT_PREFIX = "/_htmx_components";
|
|
2862
|
-
|
|
2863
|
-
// src/component-system/context.tsx
|
|
2864
|
-
var RenderContext = class {
|
|
2865
|
-
constructor(prefix, instanceId, componentName) {
|
|
2866
|
-
this.prefix = prefix;
|
|
2867
|
-
this.instanceId = instanceId;
|
|
2868
|
-
this.componentName = componentName;
|
|
2869
|
-
}
|
|
2870
|
-
// 生成唯一 ID(使用全局共享计数器,避免冲突)
|
|
2871
|
-
$id() {
|
|
2872
|
-
return generateUniqueId();
|
|
2873
|
-
}
|
|
2874
|
-
setState(state) {
|
|
2875
|
-
StateStore.get().setState(this.instanceId, state);
|
|
2876
|
-
}
|
|
2877
|
-
get state() {
|
|
2878
|
-
return StateStore.get().getState(this.instanceId).data.state;
|
|
2879
|
-
}
|
|
2880
|
-
get props() {
|
|
2881
|
-
return StateStore.get().getState(this.instanceId).data.props;
|
|
2882
|
-
}
|
|
2883
|
-
// 生成方法 URL(使用当前 instanceId)
|
|
2884
|
-
url(methodName, params) {
|
|
2885
|
-
const baseUrl = `${this.prefix}/${HTMX_COMPONENT_PREFIX}/${this.componentName}/${this.instanceId}/${methodName}`;
|
|
2886
|
-
if (params && Object.keys(params).length > 0) {
|
|
2887
|
-
const queryString = new URLSearchParams(
|
|
2888
|
-
Object.entries(params).reduce(
|
|
2889
|
-
(acc, [key, value]) => {
|
|
2890
|
-
acc[key] = String(value);
|
|
2891
|
-
return acc;
|
|
2892
|
-
},
|
|
2893
|
-
{}
|
|
2894
|
-
)
|
|
2895
|
-
).toString();
|
|
2896
|
-
return `${baseUrl}?${queryString}`;
|
|
2897
|
-
}
|
|
2898
|
-
return baseUrl;
|
|
2899
|
-
}
|
|
2900
|
-
callMethod(methodName, params) {
|
|
2901
|
-
const selectors = Object.entries(params).map(([name, expression]) => `${name}:${expression}`).join(",");
|
|
2902
|
-
return {
|
|
2903
|
-
"hx-post": this.url(methodName),
|
|
2904
|
-
"hx-vals": `js:{_params_:{${selectors}}}`,
|
|
2905
|
-
"hx-params": "_state_,_params_,_this_value_"
|
|
2906
|
-
};
|
|
2907
|
-
}
|
|
2908
|
-
};
|
|
2909
|
-
var ComponentContext = class extends RenderContext {
|
|
2910
|
-
constructor(prefix, ctx, componentName) {
|
|
2911
|
-
const routeParams = ctx.req.param();
|
|
2912
|
-
const instanceId = String(routeParams.instanceId || "");
|
|
2913
|
-
super(prefix, instanceId, componentName);
|
|
2914
|
-
this.ctx = ctx;
|
|
2915
|
-
}
|
|
2916
|
-
// 获取所有参数(统一接口:聚合 query string 和 body)
|
|
2917
|
-
async params() {
|
|
2918
|
-
const params = {};
|
|
2919
|
-
const routeParams = this.ctx.req.param();
|
|
2920
|
-
Object.assign(params, routeParams);
|
|
2921
|
-
const url = new URL(this.ctx.req.url);
|
|
2922
|
-
for (const [key, value] of url.searchParams.entries()) {
|
|
2923
|
-
params[key] = value;
|
|
2924
|
-
}
|
|
2925
|
-
const contentType = this.ctx.req.header("Content-Type") || "";
|
|
2926
|
-
if (contentType.includes("application/json")) {
|
|
2927
|
-
try {
|
|
2928
|
-
const body = await this.ctx.req.json();
|
|
2929
|
-
Object.assign(params, body);
|
|
2930
|
-
} catch (e) {
|
|
2931
|
-
console.warn("[ComponentContext] Failed to parse JSON body:", e);
|
|
2932
|
-
}
|
|
2933
|
-
} else if (this.ctx.req.method === "POST" || this.ctx.req.method === "PUT" || this.ctx.req.method === "PATCH" || this.ctx.req.method === "DELETE") {
|
|
2934
|
-
try {
|
|
2935
|
-
const formData = await this.ctx.req.formData();
|
|
2936
|
-
for (const [key, value] of formData.entries()) {
|
|
2937
|
-
params[key] = value instanceof File ? value : value.toString();
|
|
2938
|
-
}
|
|
2939
|
-
} catch (e) {
|
|
2940
|
-
console.warn("[ComponentContext] Failed to parse form data:", e);
|
|
2941
|
-
}
|
|
2942
|
-
}
|
|
2943
|
-
return params;
|
|
2944
|
-
}
|
|
2945
|
-
// 获取查询参数
|
|
2946
|
-
query() {
|
|
2947
|
-
const url = new URL(this.ctx.req.url);
|
|
2948
|
-
return Object.fromEntries(url.searchParams.entries());
|
|
2949
|
-
}
|
|
2950
|
-
// 获取请求体
|
|
2951
|
-
async body() {
|
|
2952
|
-
const contentType = this.ctx.req.header("Content-Type") || "";
|
|
2953
|
-
if (contentType.includes("application/json")) {
|
|
2954
|
-
try {
|
|
2955
|
-
return await this.ctx.req.json();
|
|
2956
|
-
} catch (e) {
|
|
2957
|
-
console.warn("[ComponentContext] Failed to parse JSON body:", e);
|
|
2958
|
-
return {};
|
|
2959
|
-
}
|
|
2960
|
-
}
|
|
2961
|
-
try {
|
|
2962
|
-
const formData = await this.ctx.req.formData();
|
|
2963
|
-
const body = {};
|
|
2964
|
-
for (const [key, value] of formData.entries()) {
|
|
2965
|
-
body[key] = value instanceof File ? value : value.toString();
|
|
2966
|
-
}
|
|
2967
|
-
return body;
|
|
2968
|
-
} catch (e) {
|
|
2969
|
-
console.warn("[ComponentContext] Failed to parse form data:", e);
|
|
2970
|
-
return {};
|
|
2971
|
-
}
|
|
2972
|
-
}
|
|
2973
|
-
};
|
|
2974
|
-
|
|
2975
|
-
// src/component-system/component.tsx
|
|
2976
|
-
var METHOD_METADATA_KEY = /* @__PURE__ */ Symbol("htmx:method");
|
|
2977
|
-
function Method(config) {
|
|
2978
|
-
return function(target, propertyKey, _descriptor) {
|
|
2979
|
-
if (!target[METHOD_METADATA_KEY]) {
|
|
2980
|
-
target[METHOD_METADATA_KEY] = /* @__PURE__ */ new Map();
|
|
2981
|
-
}
|
|
2982
|
-
target[METHOD_METADATA_KEY].set(propertyKey, {
|
|
2983
|
-
method: config?.method || "get",
|
|
2984
|
-
path: config?.path
|
|
2985
|
-
});
|
|
2986
|
-
};
|
|
2987
|
-
}
|
|
2988
|
-
var HtmxComponent = class {
|
|
2989
|
-
constructor(name) {
|
|
2990
|
-
this.name = name;
|
|
2991
|
-
}
|
|
2992
|
-
prefix;
|
|
2993
|
-
// 组件函数
|
|
2994
|
-
Component = (props) => {
|
|
2995
|
-
const instanceId = generateUniqueId();
|
|
2996
|
-
const state = StateStore.get().getState(instanceId).data;
|
|
2997
|
-
state.props = props;
|
|
2998
|
-
state.state = {};
|
|
2999
|
-
const renderCtx = new RenderContext(
|
|
3000
|
-
this.prefix,
|
|
3001
|
-
instanceId,
|
|
3002
|
-
this.name
|
|
3003
|
-
);
|
|
3004
|
-
return this.render(renderCtx, props);
|
|
3005
|
-
};
|
|
3006
|
-
// 返回 JSX script 元素
|
|
3007
|
-
// 获取所有标记为 @Method() 的方法
|
|
3008
|
-
// 注意:handler 不再绑定 this,因为方法会接收 ComponentContext 作为第一个参数
|
|
3009
|
-
static getMethods(component) {
|
|
3010
|
-
const methods = /* @__PURE__ */ new Map();
|
|
3011
|
-
const metadata = component[METHOD_METADATA_KEY];
|
|
3012
|
-
if (!metadata) return methods;
|
|
3013
|
-
for (const [methodName, config] of metadata.entries()) {
|
|
3014
|
-
const handler = component[methodName];
|
|
3015
|
-
methods.set(methodName, {
|
|
3016
|
-
method: config.method,
|
|
3017
|
-
path: config.path,
|
|
3018
|
-
handler
|
|
3019
|
-
});
|
|
3020
|
-
}
|
|
3021
|
-
return methods;
|
|
3022
|
-
}
|
|
3023
|
-
};
|
|
3024
|
-
var HtmxComponentHandler = class {
|
|
3025
|
-
constructor(hono, prefix, components) {
|
|
3026
|
-
this.hono = hono;
|
|
3027
|
-
this.prefix = prefix;
|
|
3028
|
-
this.components = components;
|
|
3029
|
-
for (const component of this.components) {
|
|
3030
|
-
component.prefix = this.prefix;
|
|
3031
|
-
this.registerHandler(component);
|
|
3032
|
-
}
|
|
3033
|
-
}
|
|
3034
|
-
registerHandler(component) {
|
|
3035
|
-
const methods = HtmxComponent.getMethods(component);
|
|
3036
|
-
for (const [methodName, methodConfig] of methods) {
|
|
3037
|
-
const routePath = `${this.prefix}/${HTMX_COMPONENT_PREFIX}/${component.name}/:instanceId/${methodName}`;
|
|
3038
|
-
logger.info(
|
|
3039
|
-
`[HtmxComponent] Registering handler ${methodConfig.method} ${routePath}`
|
|
3040
|
-
);
|
|
3041
|
-
this.hono[methodConfig.method](routePath, async (ctx) => {
|
|
3042
|
-
return this.handleComponentMethod(
|
|
3043
|
-
ctx,
|
|
3044
|
-
component,
|
|
3045
|
-
methodConfig.handler.bind(component)
|
|
3046
|
-
);
|
|
3047
|
-
});
|
|
3048
|
-
}
|
|
3049
|
-
}
|
|
3050
|
-
async handleComponentMethod(ctx, component, handler) {
|
|
3051
|
-
const componentContext = new ComponentContext(
|
|
3052
|
-
this.prefix,
|
|
3053
|
-
ctx,
|
|
3054
|
-
component.name
|
|
3055
|
-
);
|
|
3056
|
-
const result = await handler(componentContext);
|
|
3057
|
-
if (result instanceof Object && ("target" in result || "swap" in result || "body" in result || "oobs" in result)) {
|
|
3058
|
-
const { target, swap, body, oobs, trigger } = result;
|
|
3059
|
-
const headers = {};
|
|
3060
|
-
let bodyContent = body;
|
|
3061
|
-
if (target) headers["HX-Retarget"] = target;
|
|
3062
|
-
if (swap) headers["HX-Reswap"] = swap;
|
|
3063
|
-
if (trigger) headers["HX-Trigger"] = trigger;
|
|
3064
|
-
if (oobs) {
|
|
3065
|
-
oobs.forEach((oob) => {
|
|
3066
|
-
oob.props["hx-swap-oob"] = "true";
|
|
3067
|
-
});
|
|
3068
|
-
if (!body) {
|
|
3069
|
-
headers["HX-Reswap"] = "delete";
|
|
3070
|
-
}
|
|
3071
|
-
bodyContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3072
|
-
body,
|
|
3073
|
-
oobs
|
|
3074
|
-
] });
|
|
3075
|
-
}
|
|
3076
|
-
return ctx.html(bodyContent, 200, headers);
|
|
3077
|
-
}
|
|
3078
|
-
if (result === null) {
|
|
3079
|
-
return ctx.html(/* @__PURE__ */ jsx("div", {}), 200, {
|
|
3080
|
-
"HX-Reswap": "none"
|
|
3081
|
-
});
|
|
3082
|
-
}
|
|
3083
|
-
if (result instanceof Response) {
|
|
3084
|
-
return result;
|
|
3085
|
-
}
|
|
3086
|
-
return ctx.html(result, 200);
|
|
3087
|
-
}
|
|
3088
|
-
};
|
|
3089
|
-
|
|
3090
2817
|
// src/utils/path.ts
|
|
3091
2818
|
function modelNameToPath(modelName) {
|
|
3092
2819
|
return `/${modelName.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
|
|
@@ -3098,8 +2825,9 @@ function ErrorAlert(props) {
|
|
|
3098
2825
|
type = "error",
|
|
3099
2826
|
showClose = true,
|
|
3100
2827
|
className = "",
|
|
3101
|
-
autoClose = 5e3
|
|
2828
|
+
autoClose = 5e3,
|
|
3102
2829
|
// 默认 5 秒自动关闭
|
|
2830
|
+
"hx-swap-oob": hxSwapOob
|
|
3103
2831
|
} = props;
|
|
3104
2832
|
const typeClasses = {
|
|
3105
2833
|
error: "bg-red-50 border-red-200 text-red-800",
|
|
@@ -3188,12 +2916,20 @@ function ErrorAlert(props) {
|
|
|
3188
2916
|
const now = Date.now();
|
|
3189
2917
|
this.elapsedTime = now - this.startTime;
|
|
3190
2918
|
this.progress = Math.max(0, 100 - (this.elapsedTime / this.autoCloseDelay) * 100);
|
|
2919
|
+
// \u66F4\u65B0\u8FDB\u5EA6\u6761\u6837\u5F0F
|
|
2920
|
+
const progressBar = this.$el.querySelector('.progress-bar');
|
|
2921
|
+
if (progressBar) {
|
|
2922
|
+
progressBar.style.width = this.progress + '%';
|
|
2923
|
+
}
|
|
3191
2924
|
if (this.progress > 0 && this.visible) {
|
|
3192
2925
|
this.progressTimer = requestAnimationFrame(updateProgress);
|
|
3193
2926
|
}
|
|
3194
2927
|
};
|
|
3195
2928
|
this.progressTimer = requestAnimationFrame(updateProgress);
|
|
3196
2929
|
},
|
|
2930
|
+
getProgressStyle() {
|
|
2931
|
+
return { width: this.progress + '%' };
|
|
2932
|
+
},
|
|
3197
2933
|
pauseAutoClose() {
|
|
3198
2934
|
if (this.autoCloseTimer) {
|
|
3199
2935
|
clearTimeout(this.autoCloseTimer);
|
|
@@ -3222,6 +2958,9 @@ function ErrorAlert(props) {
|
|
|
3222
2958
|
cancelAnimationFrame(this.progressTimer);
|
|
3223
2959
|
this.progressTimer = null;
|
|
3224
2960
|
}
|
|
2961
|
+
// \u6DFB\u52A0\u6DE1\u51FA\u52A8\u753B
|
|
2962
|
+
this.$el.classList.add('error-alert-exit');
|
|
2963
|
+
// \u52A8\u753B\u7ED3\u675F\u540E\u5B8C\u5168\u79FB\u9664\u5143\u7D20\uFF0C\u4E0D\u7559\u7A7A div
|
|
3225
2964
|
setTimeout(() => {
|
|
3226
2965
|
if (this.$el && this.$el.parentNode) {
|
|
3227
2966
|
this.$el.parentNode.removeChild(this.$el);
|
|
@@ -3232,6 +2971,9 @@ function ErrorAlert(props) {
|
|
|
3232
2971
|
visible: true,
|
|
3233
2972
|
close() {
|
|
3234
2973
|
this.visible = false;
|
|
2974
|
+
// \u6DFB\u52A0\u6DE1\u51FA\u52A8\u753B
|
|
2975
|
+
this.$el.classList.add('error-alert-exit');
|
|
2976
|
+
// \u52A8\u753B\u7ED3\u675F\u540E\u5B8C\u5168\u79FB\u9664\u5143\u7D20\uFF0C\u4E0D\u7559\u7A7A div
|
|
3235
2977
|
setTimeout(() => {
|
|
3236
2978
|
if (this.$el && this.$el.parentNode) {
|
|
3237
2979
|
this.$el.parentNode.removeChild(this.$el);
|
|
@@ -3253,18 +2995,26 @@ function ErrorAlert(props) {
|
|
|
3253
2995
|
alpineProps["@mouseenter"] = "pauseAutoClose()";
|
|
3254
2996
|
alpineProps["@mouseleave"] = "resumeAutoClose()";
|
|
3255
2997
|
}
|
|
2998
|
+
const htmxProps = {};
|
|
2999
|
+
if (hxSwapOob) {
|
|
3000
|
+
htmxProps["hx-swap-oob"] = hxSwapOob;
|
|
3001
|
+
}
|
|
3256
3002
|
return /* @__PURE__ */ jsxs(
|
|
3257
3003
|
"div",
|
|
3258
3004
|
{
|
|
3259
3005
|
...alpineProps,
|
|
3260
|
-
|
|
3006
|
+
...htmxProps,
|
|
3007
|
+
className: `w-full border rounded-lg p-4 shadow-lg ${typeClasses[type]} ${className} relative overflow-hidden pointer-events-auto`,
|
|
3261
3008
|
role: "alert",
|
|
3009
|
+
style: {
|
|
3010
|
+
animation: "slideInRight 0.3s ease-out"
|
|
3011
|
+
},
|
|
3262
3012
|
children: [
|
|
3263
3013
|
autoClose > 0 && /* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 right-0 h-1 bg-gray-200", children: /* @__PURE__ */ jsx(
|
|
3264
3014
|
"div",
|
|
3265
3015
|
{
|
|
3266
|
-
className: `h-full ${progressBarColors[type]}`,
|
|
3267
|
-
...{ ":style": "
|
|
3016
|
+
className: `h-full ${progressBarColors[type]} progress-bar`,
|
|
3017
|
+
...{ "x-bind:style": "getProgressStyle()" }
|
|
3268
3018
|
}
|
|
3269
3019
|
) }),
|
|
3270
3020
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start", children: [
|
|
@@ -3383,6 +3133,9 @@ async function createFeatureContext(ctx, page, feature, user, options) {
|
|
|
3383
3133
|
};
|
|
3384
3134
|
return featureContext;
|
|
3385
3135
|
}
|
|
3136
|
+
function generateDialogId() {
|
|
3137
|
+
return `dialog-${Date.now()}}`;
|
|
3138
|
+
}
|
|
3386
3139
|
function Dialog(props) {
|
|
3387
3140
|
const {
|
|
3388
3141
|
title,
|
|
@@ -3394,6 +3147,7 @@ function Dialog(props) {
|
|
|
3394
3147
|
actions = [],
|
|
3395
3148
|
fixedContentHeight = false
|
|
3396
3149
|
} = props;
|
|
3150
|
+
const dialogId = generateDialogId();
|
|
3397
3151
|
const sizeClasses = {
|
|
3398
3152
|
sm: "max-w-md",
|
|
3399
3153
|
md: "max-w-lg",
|
|
@@ -3401,19 +3155,33 @@ function Dialog(props) {
|
|
|
3401
3155
|
xl: "max-w-4xl",
|
|
3402
3156
|
full: "max-w-7xl"
|
|
3403
3157
|
};
|
|
3404
|
-
const
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3158
|
+
const alpineData = `{
|
|
3159
|
+
closeDialog() {
|
|
3160
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
3161
|
+
if (backdrop) {
|
|
3162
|
+
backdrop.classList.add('dialog-exit');
|
|
3163
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
3164
|
+
if (content) {
|
|
3165
|
+
content.classList.add('dialog-content-exit');
|
|
3166
|
+
}
|
|
3167
|
+
setTimeout(() => {
|
|
3168
|
+
backdrop.remove();
|
|
3169
|
+
}, 200);
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
}`;
|
|
3409
3173
|
return /* @__PURE__ */ jsx(
|
|
3410
3174
|
"div",
|
|
3411
3175
|
{
|
|
3176
|
+
id: dialogId,
|
|
3412
3177
|
className: "fixed inset-0 bg-black bg-opacity-50 z-[100] flex items-center justify-center p-4 dialog-backdrop",
|
|
3413
3178
|
style: {
|
|
3414
3179
|
animation: "fadeIn 0.2s ease-out"
|
|
3415
3180
|
},
|
|
3416
|
-
|
|
3181
|
+
"x-data": alpineData,
|
|
3182
|
+
...closeOnBackdropClick && {
|
|
3183
|
+
"x-on:click": "if ($event.target === $el) closeDialog()"
|
|
3184
|
+
},
|
|
3417
3185
|
children: /* @__PURE__ */ jsxs(
|
|
3418
3186
|
"div",
|
|
3419
3187
|
{
|
|
@@ -3421,7 +3189,7 @@ function Dialog(props) {
|
|
|
3421
3189
|
style: {
|
|
3422
3190
|
animation: "slideIn 0.3s ease-out"
|
|
3423
3191
|
},
|
|
3424
|
-
|
|
3192
|
+
...{ "x-on:click.stop": "" },
|
|
3425
3193
|
children: [
|
|
3426
3194
|
(title || showClose) && /* @__PURE__ */ jsxs("div", { className: "px-6 py-4 border-b border-gray-200 bg-white flex items-center justify-between", children: [
|
|
3427
3195
|
title && /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-900", children: title }),
|
|
@@ -3429,7 +3197,7 @@ function Dialog(props) {
|
|
|
3429
3197
|
"button",
|
|
3430
3198
|
{
|
|
3431
3199
|
className: "text-gray-400 hover:text-gray-600 transition-colors",
|
|
3432
|
-
|
|
3200
|
+
"x-on:click": "closeDialog()",
|
|
3433
3201
|
children: /* @__PURE__ */ jsx(
|
|
3434
3202
|
"svg",
|
|
3435
3203
|
{
|
|
@@ -3526,11 +3294,26 @@ function PermissionDeniedContent(props) {
|
|
|
3526
3294
|
Button,
|
|
3527
3295
|
{
|
|
3528
3296
|
variant: "secondary",
|
|
3529
|
-
|
|
3297
|
+
"x-data": `{
|
|
3298
|
+
closeDialog() {
|
|
3299
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
3300
|
+
if (backdrop) {
|
|
3301
|
+
backdrop.classList.add('dialog-exit');
|
|
3302
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
3303
|
+
if (content) {
|
|
3304
|
+
content.classList.add('dialog-content-exit');
|
|
3305
|
+
}
|
|
3306
|
+
setTimeout(() => {
|
|
3307
|
+
backdrop.remove();
|
|
3308
|
+
}, 200);
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
}`,
|
|
3312
|
+
"x-on:click": "closeDialog()",
|
|
3530
3313
|
children: "\u5173\u95ED"
|
|
3531
3314
|
}
|
|
3532
3315
|
),
|
|
3533
|
-
!isDialog && userInfo && /* @__PURE__ */ jsx(Button, { variant: "secondary",
|
|
3316
|
+
!isDialog && userInfo && /* @__PURE__ */ jsx(Button, { variant: "secondary", onclick: "window.history.back()", children: "\u8FD4\u56DE" })
|
|
3534
3317
|
] })
|
|
3535
3318
|
] });
|
|
3536
3319
|
}
|
|
@@ -3551,13 +3334,8 @@ var getResourceUrl = (prefix, name) => {
|
|
|
3551
3334
|
function globalScripts(prefix) {
|
|
3552
3335
|
return html`
|
|
3553
3336
|
<script src=${getResourceUrl(prefix, "htmx")}></script>
|
|
3554
|
-
<script src=${getResourceUrl(prefix, "htmx-ext-form-json")}></script>
|
|
3555
|
-
<script src=${getResourceUrl(prefix, "hyperscript")}></script>
|
|
3556
3337
|
<script src=${getResourceUrl(prefix, "tailwindcss")}></script>
|
|
3557
3338
|
<script src=${getResourceUrl(prefix, "alpinejs")} defer></script>
|
|
3558
|
-
<script src=${getResourceUrl(prefix, "sortablejs")}></script>
|
|
3559
|
-
<script src=${getResourceUrl(prefix, "idiomorph")}></script>
|
|
3560
|
-
<script type="module" src=${getResourceUrl(prefix, "datastar")}></script>
|
|
3561
3339
|
`;
|
|
3562
3340
|
}
|
|
3563
3341
|
function globalStyles() {
|
|
@@ -3687,36 +3465,6 @@ function globalStyles() {
|
|
|
3687
3465
|
}
|
|
3688
3466
|
</style>`;
|
|
3689
3467
|
}
|
|
3690
|
-
function sortableScript() {
|
|
3691
|
-
html`<script>
|
|
3692
|
-
if (typeof htmx !== "undefined" && typeof Sortable !== "undefined") {
|
|
3693
|
-
htmx.onLoad(function (content) {
|
|
3694
|
-
var sortables = content.querySelectorAll(".sortable");
|
|
3695
|
-
for (var i = 0; i < sortables.length; i++) {
|
|
3696
|
-
var sortable = sortables[i];
|
|
3697
|
-
// 检查是否已经初始化
|
|
3698
|
-
if (sortable.sortableInstance) {
|
|
3699
|
-
continue;
|
|
3700
|
-
}
|
|
3701
|
-
var sortableInstance = new Sortable(sortable, {
|
|
3702
|
-
animation: 150,
|
|
3703
|
-
ghostClass: "sortable-ghost",
|
|
3704
|
-
filter: ".htmx-indicator",
|
|
3705
|
-
onMove: function (evt) {
|
|
3706
|
-
return evt.related.className.indexOf("htmx-indicator") === -1;
|
|
3707
|
-
},
|
|
3708
|
-
});
|
|
3709
|
-
sortable.sortableInstance = sortableInstance;
|
|
3710
|
-
sortable.addEventListener("htmx:afterSwap", function () {
|
|
3711
|
-
if (sortable.sortableInstance) {
|
|
3712
|
-
sortable.sortableInstance.option("disabled", false);
|
|
3713
|
-
}
|
|
3714
|
-
});
|
|
3715
|
-
}
|
|
3716
|
-
});
|
|
3717
|
-
}
|
|
3718
|
-
</script>`;
|
|
3719
|
-
}
|
|
3720
3468
|
function Breadcrumb(props) {
|
|
3721
3469
|
const { items } = props;
|
|
3722
3470
|
if (items.length === 0) {
|
|
@@ -4072,193 +3820,183 @@ function SortableList(props) {
|
|
|
4072
3820
|
function StringArrayEditor(props) {
|
|
4073
3821
|
const {
|
|
4074
3822
|
value,
|
|
4075
|
-
fieldName,
|
|
4076
3823
|
placeholder = "\u8BF7\u8F93\u5165\u5185\u5BB9",
|
|
4077
3824
|
allowEmpty = false,
|
|
4078
3825
|
rows = 1
|
|
4079
3826
|
} = props;
|
|
3827
|
+
const name = props.name;
|
|
4080
3828
|
const initialItems = value || [];
|
|
4081
3829
|
const initialDataJson = JSON.stringify({
|
|
4082
3830
|
items: initialItems.map((item) => item || ""),
|
|
4083
|
-
fieldName,
|
|
3831
|
+
fieldName: name,
|
|
4084
3832
|
placeholder,
|
|
4085
3833
|
allowEmpty,
|
|
4086
3834
|
rows
|
|
4087
3835
|
});
|
|
4088
|
-
return /* @__PURE__ */ jsxs(
|
|
4089
|
-
"div",
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
"button",
|
|
4096
|
-
{
|
|
4097
|
-
type: "button",
|
|
4098
|
-
...{
|
|
4099
|
-
"x-on:click": `
|
|
3836
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", "x-data": initialDataJson, children: [
|
|
3837
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsxs(
|
|
3838
|
+
"button",
|
|
3839
|
+
{
|
|
3840
|
+
type: "button",
|
|
3841
|
+
...{
|
|
3842
|
+
"x-on:click": `
|
|
4100
3843
|
items.push('');
|
|
4101
3844
|
`
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
3845
|
+
},
|
|
3846
|
+
className: "px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium flex items-center gap-2",
|
|
3847
|
+
"data-testid": `${name}-add-button`,
|
|
3848
|
+
children: [
|
|
3849
|
+
/* @__PURE__ */ jsx(
|
|
3850
|
+
"svg",
|
|
3851
|
+
{
|
|
3852
|
+
className: "w-4 h-4",
|
|
3853
|
+
fill: "none",
|
|
3854
|
+
stroke: "currentColor",
|
|
3855
|
+
viewBox: "0 0 24 24",
|
|
3856
|
+
children: /* @__PURE__ */ jsx(
|
|
3857
|
+
"path",
|
|
4108
3858
|
{
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
children: /* @__PURE__ */ jsx(
|
|
4114
|
-
"path",
|
|
4115
|
-
{
|
|
4116
|
-
strokeLinecap: "round",
|
|
4117
|
-
strokeLinejoin: "round",
|
|
4118
|
-
strokeWidth: "2",
|
|
4119
|
-
d: "M12 4v16m8-8H4"
|
|
4120
|
-
}
|
|
4121
|
-
)
|
|
3859
|
+
strokeLinecap: "round",
|
|
3860
|
+
strokeLinejoin: "round",
|
|
3861
|
+
strokeWidth: "2",
|
|
3862
|
+
d: "M12 4v16m8-8H4"
|
|
4122
3863
|
}
|
|
4123
|
-
)
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
3864
|
+
)
|
|
3865
|
+
}
|
|
3866
|
+
),
|
|
3867
|
+
"\u6DFB\u52A0\u9879"
|
|
3868
|
+
]
|
|
3869
|
+
}
|
|
3870
|
+
) }),
|
|
3871
|
+
/* @__PURE__ */ jsx(
|
|
3872
|
+
"div",
|
|
3873
|
+
{
|
|
3874
|
+
"x-show": "items.length > 0",
|
|
3875
|
+
"data-testid": `${name}-list-container`,
|
|
3876
|
+
...{
|
|
3877
|
+
"@sortable:change.stop": `
|
|
4135
3878
|
(function() {
|
|
4136
3879
|
const { oldIndex, newIndex } = $event.detail;
|
|
4137
3880
|
[items[oldIndex], items[newIndex]] = [items[newIndex], items[oldIndex]];
|
|
4138
3881
|
})();
|
|
4139
3882
|
`
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
}
|
|
4155
|
-
);
|
|
3883
|
+
},
|
|
3884
|
+
children: /* @__PURE__ */ jsx(SortableList, { className: "space-y-2", handle: "[data-drag-handle]", children: /* @__PURE__ */ jsx("template", { "x-for": "(item, index) in items", "x-bind:key": "index", children: /* @__PURE__ */ jsx(ArrayItem, { fieldName: name, rows }) }) })
|
|
3885
|
+
}
|
|
3886
|
+
),
|
|
3887
|
+
/* @__PURE__ */ jsx(
|
|
3888
|
+
"div",
|
|
3889
|
+
{
|
|
3890
|
+
className: "empty-state text-center py-8 text-gray-400 text-sm border border-dashed border-gray-300 rounded-lg",
|
|
3891
|
+
"x-show": "items.length === 0",
|
|
3892
|
+
"data-testid": `${name}-empty-state`,
|
|
3893
|
+
children: '\u6682\u65E0\u9879\uFF0C\u70B9\u51FB"\u6DFB\u52A0\u9879"\u6309\u94AE\u6DFB\u52A0'
|
|
3894
|
+
}
|
|
3895
|
+
)
|
|
3896
|
+
] });
|
|
4156
3897
|
}
|
|
4157
|
-
function ArrayItem({
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
3898
|
+
function ArrayItem({
|
|
3899
|
+
fieldName,
|
|
3900
|
+
rows = 1
|
|
3901
|
+
}) {
|
|
3902
|
+
return /* @__PURE__ */ jsxs("div", { "data-array-item": true, className: "flex items-center gap-2 group", children: [
|
|
3903
|
+
/* @__PURE__ */ jsx(
|
|
3904
|
+
"div",
|
|
3905
|
+
{
|
|
3906
|
+
className: "flex-shrink-0 cursor-move text-gray-400 hover:text-gray-600 transition-colors p-1",
|
|
3907
|
+
"data-drag-handle": true,
|
|
3908
|
+
"data-testid": `${fieldName}-drag-handle`,
|
|
3909
|
+
title: "\u62D6\u62FD\u6392\u5E8F",
|
|
3910
|
+
children: /* @__PURE__ */ jsx(
|
|
3911
|
+
"svg",
|
|
4166
3912
|
{
|
|
4167
|
-
className: "
|
|
4168
|
-
"
|
|
4169
|
-
"
|
|
4170
|
-
|
|
3913
|
+
className: "w-5 h-5",
|
|
3914
|
+
fill: "none",
|
|
3915
|
+
stroke: "currentColor",
|
|
3916
|
+
viewBox: "0 0 24 24",
|
|
4171
3917
|
children: /* @__PURE__ */ jsx(
|
|
4172
|
-
"
|
|
3918
|
+
"path",
|
|
4173
3919
|
{
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
children: /* @__PURE__ */ jsx(
|
|
4179
|
-
"path",
|
|
4180
|
-
{
|
|
4181
|
-
strokeLinecap: "round",
|
|
4182
|
-
strokeLinejoin: "round",
|
|
4183
|
-
strokeWidth: "2",
|
|
4184
|
-
d: "M4 8h16M4 16h16"
|
|
4185
|
-
}
|
|
4186
|
-
)
|
|
3920
|
+
strokeLinecap: "round",
|
|
3921
|
+
strokeLinejoin: "round",
|
|
3922
|
+
strokeWidth: "2",
|
|
3923
|
+
d: "M4 8h16M4 16h16"
|
|
4187
3924
|
}
|
|
4188
3925
|
)
|
|
4189
3926
|
}
|
|
4190
|
-
)
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
3927
|
+
)
|
|
3928
|
+
}
|
|
3929
|
+
),
|
|
3930
|
+
rows === 1 ? /* @__PURE__ */ jsx(
|
|
3931
|
+
"input",
|
|
3932
|
+
{
|
|
3933
|
+
type: "text",
|
|
3934
|
+
"x-model": "items[index]",
|
|
3935
|
+
"x-bind:placeholder": "placeholder + ' ' + (index + 1)",
|
|
3936
|
+
className: "flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",
|
|
3937
|
+
"data-testid": `${fieldName}-input`,
|
|
3938
|
+
"x-bind:required": "!allowEmpty"
|
|
3939
|
+
}
|
|
3940
|
+
) : /* @__PURE__ */ jsx(
|
|
3941
|
+
"textarea",
|
|
3942
|
+
{
|
|
3943
|
+
"x-model": "items[index]",
|
|
3944
|
+
"x-bind:placeholder": "placeholder + ' ' + (index + 1)",
|
|
3945
|
+
rows,
|
|
3946
|
+
className: "flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-y",
|
|
3947
|
+
"data-testid": `${fieldName}-input`,
|
|
3948
|
+
"x-bind:required": "!allowEmpty"
|
|
3949
|
+
}
|
|
3950
|
+
),
|
|
3951
|
+
/* @__PURE__ */ jsx(
|
|
3952
|
+
"input",
|
|
3953
|
+
{
|
|
3954
|
+
type: "hidden",
|
|
3955
|
+
"x-bind:name": "fieldName + '[' + index + ']'",
|
|
3956
|
+
"x-bind:value": "item"
|
|
3957
|
+
}
|
|
3958
|
+
),
|
|
3959
|
+
/* @__PURE__ */ jsx(
|
|
3960
|
+
"button",
|
|
3961
|
+
{
|
|
3962
|
+
type: "button",
|
|
3963
|
+
...{
|
|
3964
|
+
"x-on:click": `
|
|
4226
3965
|
items.splice(index, 1);
|
|
4227
3966
|
`
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
3967
|
+
},
|
|
3968
|
+
className: "flex-shrink-0 px-3 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors",
|
|
3969
|
+
"data-testid": `${fieldName}-remove-button`,
|
|
3970
|
+
title: "\u5220\u9664\u6B64\u9879",
|
|
3971
|
+
children: /* @__PURE__ */ jsx(
|
|
3972
|
+
"svg",
|
|
3973
|
+
{
|
|
3974
|
+
className: "w-5 h-5",
|
|
3975
|
+
fill: "none",
|
|
3976
|
+
stroke: "currentColor",
|
|
3977
|
+
viewBox: "0 0 24 24",
|
|
4232
3978
|
children: /* @__PURE__ */ jsx(
|
|
4233
|
-
"
|
|
3979
|
+
"path",
|
|
4234
3980
|
{
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
children: /* @__PURE__ */ jsx(
|
|
4240
|
-
"path",
|
|
4241
|
-
{
|
|
4242
|
-
strokeLinecap: "round",
|
|
4243
|
-
strokeLinejoin: "round",
|
|
4244
|
-
strokeWidth: "2",
|
|
4245
|
-
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
4246
|
-
}
|
|
4247
|
-
)
|
|
3981
|
+
strokeLinecap: "round",
|
|
3982
|
+
strokeLinejoin: "round",
|
|
3983
|
+
strokeWidth: "2",
|
|
3984
|
+
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
4248
3985
|
}
|
|
4249
3986
|
)
|
|
4250
3987
|
}
|
|
4251
3988
|
)
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
);
|
|
3989
|
+
}
|
|
3990
|
+
)
|
|
3991
|
+
] });
|
|
4255
3992
|
}
|
|
4256
3993
|
function TagsEditor(props) {
|
|
4257
|
-
const { value,
|
|
3994
|
+
const { value, placeholder = "\u8F93\u5165\u6807\u7B7E\u540E\u6309\u56DE\u8F66\u6DFB\u52A0" } = props;
|
|
3995
|
+
const name = props.name;
|
|
4258
3996
|
const initialTags = value || [];
|
|
4259
3997
|
const initialDataJson = JSON.stringify({
|
|
4260
3998
|
tags: initialTags.map((tag) => tag || ""),
|
|
4261
|
-
fieldName,
|
|
3999
|
+
fieldName: name,
|
|
4262
4000
|
newTag: "",
|
|
4263
4001
|
editingIndex: null,
|
|
4264
4002
|
editingValue: "",
|
|
@@ -4285,7 +4023,7 @@ function TagsEditor(props) {
|
|
|
4285
4023
|
placeholder,
|
|
4286
4024
|
autocomplete: "off",
|
|
4287
4025
|
className: "w-full px-3 py-1.5 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",
|
|
4288
|
-
"data-testid": `${
|
|
4026
|
+
"data-testid": `${name}-input`
|
|
4289
4027
|
}
|
|
4290
4028
|
),
|
|
4291
4029
|
/* @__PURE__ */ jsx(
|
|
@@ -4294,7 +4032,7 @@ function TagsEditor(props) {
|
|
|
4294
4032
|
"x-show": "error && editingIndex === null",
|
|
4295
4033
|
"x-text": "error",
|
|
4296
4034
|
className: "text-red-600 text-sm p-2",
|
|
4297
|
-
id: `${
|
|
4035
|
+
id: `${name}-error`
|
|
4298
4036
|
}
|
|
4299
4037
|
)
|
|
4300
4038
|
] }),
|
|
@@ -4302,7 +4040,7 @@ function TagsEditor(props) {
|
|
|
4302
4040
|
"div",
|
|
4303
4041
|
{
|
|
4304
4042
|
"x-show": "tags.length > 0",
|
|
4305
|
-
"data-testid": `${
|
|
4043
|
+
"data-testid": `${name}-tags-container`,
|
|
4306
4044
|
...{
|
|
4307
4045
|
"@sortable:change.stop": `
|
|
4308
4046
|
(function() {
|
|
@@ -4325,8 +4063,8 @@ function TagsEditor(props) {
|
|
|
4325
4063
|
"x-bind:value": "editingIndex === index ? editingValue : tag"
|
|
4326
4064
|
}
|
|
4327
4065
|
),
|
|
4328
|
-
/* @__PURE__ */ jsx(TagItem, { fieldName }),
|
|
4329
|
-
/* @__PURE__ */ jsx(TagItemEdit, { fieldName })
|
|
4066
|
+
/* @__PURE__ */ jsx(TagItem, { fieldName: name }),
|
|
4067
|
+
/* @__PURE__ */ jsx(TagItemEdit, { fieldName: name })
|
|
4330
4068
|
] }) })
|
|
4331
4069
|
}
|
|
4332
4070
|
)
|
|
@@ -4337,7 +4075,7 @@ function TagsEditor(props) {
|
|
|
4337
4075
|
{
|
|
4338
4076
|
className: "empty-state text-center py-4 text-gray-400 text-sm border border-dashed border-gray-300 rounded-md",
|
|
4339
4077
|
"x-show": "tags.length === 0",
|
|
4340
|
-
"data-testid": `${
|
|
4078
|
+
"data-testid": `${name}-empty-state`,
|
|
4341
4079
|
children: "\u6682\u65E0\u6807\u7B7E\uFF0C\u5728\u4E0A\u65B9\u8F93\u5165\u6846\u4E2D\u8F93\u5165\u6807\u7B7E\u540E\u6309\u56DE\u8F66\u6DFB\u52A0"
|
|
4342
4080
|
}
|
|
4343
4081
|
)
|
|
@@ -4518,7 +4256,7 @@ function TagItemEdit({ fieldName }) {
|
|
|
4518
4256
|
);
|
|
4519
4257
|
}
|
|
4520
4258
|
function ObjectEditor(props) {
|
|
4521
|
-
const { value,
|
|
4259
|
+
const { value, name, objectSchema } = props;
|
|
4522
4260
|
if (!objectSchema) {
|
|
4523
4261
|
return /* @__PURE__ */ jsx("div", { className: "p-4 border border-yellow-300 rounded-lg bg-yellow-50 text-yellow-800 text-sm", children: "\u8BF7\u63D0\u4F9B objectSchema \u53C2\u6570\u4EE5\u4F7F\u7528\u5BF9\u8C61\u7F16\u8F91\u5668" });
|
|
4524
4262
|
}
|
|
@@ -4538,7 +4276,7 @@ function ObjectEditor(props) {
|
|
|
4538
4276
|
const initialValueJson = JSON.stringify(initialObject);
|
|
4539
4277
|
JSON.stringify(fields.map((f) => f.name));
|
|
4540
4278
|
const generateField = (field) => {
|
|
4541
|
-
const fieldId = `${
|
|
4279
|
+
const fieldId = `${String(name)}-${field.name}`;
|
|
4542
4280
|
const fieldValue = initialObject[field.name];
|
|
4543
4281
|
const fieldValueStr = fieldValue === void 0 || fieldValue === null ? "" : typeof fieldValue === "object" ? JSON.stringify(fieldValue) : String(fieldValue);
|
|
4544
4282
|
const requiredAttr = field.required ? "required" : "";
|
|
@@ -4548,11 +4286,11 @@ function ObjectEditor(props) {
|
|
|
4548
4286
|
<input
|
|
4549
4287
|
type="text"
|
|
4550
4288
|
id="${fieldId}"
|
|
4551
|
-
name="${
|
|
4289
|
+
name="${name}.${field.name}"
|
|
4552
4290
|
value="${fieldValueStr}"
|
|
4553
4291
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4554
|
-
data-testid="${
|
|
4555
|
-
oninput="updateObjectField('${
|
|
4292
|
+
data-testid="${name}-input-${field.name}"
|
|
4293
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4556
4294
|
${requiredAttr}
|
|
4557
4295
|
/>
|
|
4558
4296
|
`;
|
|
@@ -4560,11 +4298,11 @@ function ObjectEditor(props) {
|
|
|
4560
4298
|
inputElement = html`
|
|
4561
4299
|
<textarea
|
|
4562
4300
|
id="${fieldId}"
|
|
4563
|
-
name="${
|
|
4301
|
+
name="${name}.${field.name}"
|
|
4564
4302
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-y"
|
|
4565
4303
|
rows="4"
|
|
4566
|
-
data-testid="${
|
|
4567
|
-
oninput="updateObjectField('${
|
|
4304
|
+
data-testid="${name}-input-${field.name}"
|
|
4305
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4568
4306
|
${requiredAttr}
|
|
4569
4307
|
>${fieldValueStr}</textarea>
|
|
4570
4308
|
`;
|
|
@@ -4574,12 +4312,12 @@ function ObjectEditor(props) {
|
|
|
4574
4312
|
<input
|
|
4575
4313
|
type="number"
|
|
4576
4314
|
id="${fieldId}"
|
|
4577
|
-
name="${
|
|
4315
|
+
name="${name}.${field.name}"
|
|
4578
4316
|
value="${fieldValueStr}"
|
|
4579
4317
|
step="${step}"
|
|
4580
4318
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4581
|
-
data-testid="${
|
|
4582
|
-
oninput="updateObjectField('${
|
|
4319
|
+
data-testid="${name}-input-${field.name}"
|
|
4320
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'number', ${field.required})"
|
|
4583
4321
|
${requiredAttr}
|
|
4584
4322
|
/>
|
|
4585
4323
|
`;
|
|
@@ -4588,11 +4326,11 @@ function ObjectEditor(props) {
|
|
|
4588
4326
|
<input
|
|
4589
4327
|
type="date"
|
|
4590
4328
|
id="${fieldId}"
|
|
4591
|
-
name="${
|
|
4329
|
+
name="${name}.${field.name}"
|
|
4592
4330
|
value="${fieldValueStr}"
|
|
4593
4331
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4594
|
-
data-testid="${
|
|
4595
|
-
oninput="updateObjectField('${
|
|
4332
|
+
data-testid="${name}-input-${field.name}"
|
|
4333
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'date', ${field.required})"
|
|
4596
4334
|
${requiredAttr}
|
|
4597
4335
|
/>
|
|
4598
4336
|
`;
|
|
@@ -4601,11 +4339,11 @@ function ObjectEditor(props) {
|
|
|
4601
4339
|
<input
|
|
4602
4340
|
type="email"
|
|
4603
4341
|
id="${fieldId}"
|
|
4604
|
-
name="${
|
|
4342
|
+
name="${name}.${field.name}"
|
|
4605
4343
|
value="${fieldValueStr}"
|
|
4606
4344
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4607
|
-
data-testid="${
|
|
4608
|
-
oninput="updateObjectField('${
|
|
4345
|
+
data-testid="${name}-input-${field.name}"
|
|
4346
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4609
4347
|
${requiredAttr}
|
|
4610
4348
|
/>
|
|
4611
4349
|
`;
|
|
@@ -4613,10 +4351,10 @@ function ObjectEditor(props) {
|
|
|
4613
4351
|
inputElement = html`
|
|
4614
4352
|
<select
|
|
4615
4353
|
id="${fieldId}"
|
|
4616
|
-
name="${
|
|
4354
|
+
name="${name}.${field.name}"
|
|
4617
4355
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white"
|
|
4618
|
-
data-testid="${
|
|
4619
|
-
onchange="updateObjectField('${
|
|
4356
|
+
data-testid="${name}-select-${field.name}"
|
|
4357
|
+
onchange="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4620
4358
|
${requiredAttr}
|
|
4621
4359
|
>
|
|
4622
4360
|
${!field.required ? html`<option value="">请选择</option>` : ""}
|
|
@@ -4639,11 +4377,11 @@ function ObjectEditor(props) {
|
|
|
4639
4377
|
<input
|
|
4640
4378
|
type="checkbox"
|
|
4641
4379
|
id="${fieldId}"
|
|
4642
|
-
name="${
|
|
4380
|
+
name="${name}.${field.name}"
|
|
4643
4381
|
${checked ? "checked" : ""}
|
|
4644
4382
|
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
|
|
4645
|
-
data-testid="${
|
|
4646
|
-
onchange="updateObjectField('${
|
|
4383
|
+
data-testid="${name}-checkbox-${field.name}"
|
|
4384
|
+
onchange="updateObjectField('${name}', '${field.name}', this.checked, 'checkbox', ${field.required}')"
|
|
4647
4385
|
/>
|
|
4648
4386
|
<label for="${fieldId}" class="ml-2 text-sm text-gray-700">
|
|
4649
4387
|
${field.label}
|
|
@@ -4652,12 +4390,12 @@ function ObjectEditor(props) {
|
|
|
4652
4390
|
`;
|
|
4653
4391
|
}
|
|
4654
4392
|
return html`
|
|
4655
|
-
<div class="space-y-2" data-testid="${
|
|
4393
|
+
<div class="space-y-2" data-testid="${name}-field-${field.name}">
|
|
4656
4394
|
${field.type !== "checkbox" ? html`
|
|
4657
4395
|
<label
|
|
4658
4396
|
for="${fieldId}"
|
|
4659
4397
|
class="block text-sm font-semibold text-gray-700"
|
|
4660
|
-
data-testid="${
|
|
4398
|
+
data-testid="${name}-label-${field.name}"
|
|
4661
4399
|
>
|
|
4662
4400
|
${field.label}
|
|
4663
4401
|
${field.required ? html`<span class="text-red-500 ml-1">*</span>` : ""}
|
|
@@ -4669,15 +4407,15 @@ function ObjectEditor(props) {
|
|
|
4669
4407
|
};
|
|
4670
4408
|
return html`
|
|
4671
4409
|
<div
|
|
4672
|
-
id="object-editor-${
|
|
4410
|
+
id="object-editor-${name}"
|
|
4673
4411
|
class="space-y-4"
|
|
4674
4412
|
data-initial-value="${initialValueJson}"
|
|
4675
4413
|
>
|
|
4676
4414
|
<input
|
|
4677
4415
|
type="hidden"
|
|
4678
|
-
name="${
|
|
4416
|
+
name="${name}"
|
|
4679
4417
|
value="${initialValueJson}"
|
|
4680
|
-
data-testid="hidden-${
|
|
4418
|
+
data-testid="hidden-${name}"
|
|
4681
4419
|
/>
|
|
4682
4420
|
<div class="space-y-4">
|
|
4683
4421
|
${fields.map((field) => generateField(field))}
|
|
@@ -4739,14 +4477,13 @@ function BaseLayout(props) {
|
|
|
4739
4477
|
<meta name="description" content="${props.description || ""}" />
|
|
4740
4478
|
${globalScripts(props.prefix)} ${globalStyles()}
|
|
4741
4479
|
</head>
|
|
4742
|
-
<body
|
|
4480
|
+
<body className="bg-gray-50" hx-indicator="#loading-bar">
|
|
4743
4481
|
${LoadingBar()} ${props.children}
|
|
4744
4482
|
<div
|
|
4745
|
-
id="
|
|
4746
|
-
|
|
4483
|
+
id="notification-container"
|
|
4484
|
+
style="position: fixed; top: 1rem; right: 1rem; z-index: 200; display: flex; flex-direction: column; gap: 0.5rem; pointer-events: none; width: 100%; max-width: 28rem; padding-left: 1rem; padding-right: 1rem;"
|
|
4747
4485
|
></div>
|
|
4748
4486
|
<div id="dialog-container"></div>
|
|
4749
|
-
${sortableScript()}
|
|
4750
4487
|
</body>
|
|
4751
4488
|
</html>
|
|
4752
4489
|
`;
|
|
@@ -4998,7 +4735,7 @@ async function handlePermissionDenied(ctx, result, options) {
|
|
|
4998
4735
|
if (isHtmxRequest) {
|
|
4999
4736
|
const headers = {
|
|
5000
4737
|
"HX-Retarget": "#dialog-container",
|
|
5001
|
-
"HX-Reswap": "
|
|
4738
|
+
"HX-Reswap": "beforeend",
|
|
5002
4739
|
"X-Permission-Denied": "true"
|
|
5003
4740
|
};
|
|
5004
4741
|
return ctx.html(
|
|
@@ -5043,22 +4780,15 @@ function buildNotificationFragments(notifications) {
|
|
|
5043
4780
|
if (notifications.length === 0) {
|
|
5044
4781
|
return null;
|
|
5045
4782
|
}
|
|
5046
|
-
return notifications.map((notification, index) => /* @__PURE__ */ jsx(
|
|
5047
|
-
|
|
4783
|
+
return notifications.map((notification, index) => /* @__PURE__ */ jsx("div", { id: "notification-container", "hx-swap-oob": "beforeend", children: /* @__PURE__ */ jsx(
|
|
4784
|
+
ErrorAlert,
|
|
5048
4785
|
{
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
ErrorAlert,
|
|
5053
|
-
{
|
|
5054
|
-
type: notification.type,
|
|
5055
|
-
title: notification.title,
|
|
5056
|
-
message: notification.message
|
|
5057
|
-
}
|
|
5058
|
-
)
|
|
4786
|
+
type: notification.type,
|
|
4787
|
+
title: notification.title,
|
|
4788
|
+
message: notification.message
|
|
5059
4789
|
},
|
|
5060
4790
|
`notification-${index}`
|
|
5061
|
-
));
|
|
4791
|
+
) }));
|
|
5062
4792
|
}
|
|
5063
4793
|
function isEmptyContent(result) {
|
|
5064
4794
|
if (result === null || result === void 0) return true;
|
|
@@ -5152,7 +4882,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5152
4882
|
if (context.isDialog) {
|
|
5153
4883
|
return ctx.html(
|
|
5154
4884
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5155
|
-
/* @__PURE__ */ jsx("div", { id: "dialog-container", "hx-swap-oob": "innerHTML" }),
|
|
5156
4885
|
notificationFragments,
|
|
5157
4886
|
/* @__PURE__ */ jsx("title", { children: metadata.title })
|
|
5158
4887
|
] }),
|
|
@@ -5208,7 +4937,7 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5208
4937
|
);
|
|
5209
4938
|
}
|
|
5210
4939
|
const target = context.isDialog ? "#dialog-container" : "#main-content";
|
|
5211
|
-
const swap = context.isDialog ? "
|
|
4940
|
+
const swap = context.isDialog ? "beforeend" : "outerHTML";
|
|
5212
4941
|
const headers = {
|
|
5213
4942
|
"HX-Retarget": target,
|
|
5214
4943
|
"HX-Reswap": swap
|
|
@@ -5271,7 +5000,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5271
5000
|
useAdminLayout,
|
|
5272
5001
|
currentPath,
|
|
5273
5002
|
userInfo: user,
|
|
5274
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5275
5003
|
breadcrumbs,
|
|
5276
5004
|
actions,
|
|
5277
5005
|
children: result
|
|
@@ -5307,7 +5035,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5307
5035
|
prefix: options.prefix,
|
|
5308
5036
|
title: dynamicMetadata.title,
|
|
5309
5037
|
description: dynamicMetadata.description,
|
|
5310
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5311
5038
|
children: /* @__PURE__ */ jsx(
|
|
5312
5039
|
AdminLayout,
|
|
5313
5040
|
{
|
|
@@ -5319,7 +5046,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5319
5046
|
userInfo: user,
|
|
5320
5047
|
breadcrumbs,
|
|
5321
5048
|
actions,
|
|
5322
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5323
5049
|
children: result
|
|
5324
5050
|
}
|
|
5325
5051
|
)
|
|
@@ -5334,7 +5060,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5334
5060
|
prefix: options.prefix,
|
|
5335
5061
|
title: dynamicMetadata.title,
|
|
5336
5062
|
description: dynamicMetadata.description,
|
|
5337
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5338
5063
|
children: /* @__PURE__ */ jsx(NoLayout, { children: result })
|
|
5339
5064
|
}
|
|
5340
5065
|
)
|
|
@@ -5423,14 +5148,15 @@ async function handleRequest(ctx, page, feature, handlerOptions) {
|
|
|
5423
5148
|
if (isHtmxRequest) {
|
|
5424
5149
|
return ctx.html(
|
|
5425
5150
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5426
|
-
/* @__PURE__ */ jsx(
|
|
5151
|
+
/* @__PURE__ */ jsx(
|
|
5427
5152
|
ErrorAlert,
|
|
5428
5153
|
{
|
|
5154
|
+
"hx-swap-oob": "beforeend:#notification-container",
|
|
5429
5155
|
type: "error",
|
|
5430
5156
|
title: "\u8BF7\u6C42\u5931\u8D25",
|
|
5431
5157
|
message: "Feature has no handler or render method"
|
|
5432
5158
|
}
|
|
5433
|
-
)
|
|
5159
|
+
),
|
|
5434
5160
|
/* @__PURE__ */ jsx("title", { children: "\u9519\u8BEF" })
|
|
5435
5161
|
] }),
|
|
5436
5162
|
500,
|
|
@@ -5447,10 +5173,15 @@ async function handleRequest(ctx, page, feature, handlerOptions) {
|
|
|
5447
5173
|
if (isHtmxRequest) {
|
|
5448
5174
|
const errorMessage = error instanceof Error ? error.message : "Internal server error";
|
|
5449
5175
|
return ctx.html(
|
|
5450
|
-
/* @__PURE__ */
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5176
|
+
/* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
5177
|
+
ErrorAlert,
|
|
5178
|
+
{
|
|
5179
|
+
"hx-swap-oob": "beforeend:#notification-container",
|
|
5180
|
+
type: "error",
|
|
5181
|
+
title: "\u8BF7\u6C42\u5931\u8D25",
|
|
5182
|
+
message: errorMessage
|
|
5183
|
+
}
|
|
5184
|
+
) }),
|
|
5454
5185
|
500,
|
|
5455
5186
|
{
|
|
5456
5187
|
"HX-Reswap": "none"
|
|
@@ -5553,7 +5284,6 @@ var HtmxAdminPlugin = class {
|
|
|
5553
5284
|
options;
|
|
5554
5285
|
serviceName = "";
|
|
5555
5286
|
pages = /* @__PURE__ */ new Map();
|
|
5556
|
-
componentHandler;
|
|
5557
5287
|
constructor(options) {
|
|
5558
5288
|
this.options = {
|
|
5559
5289
|
title: options?.title || "\u7BA1\u7406\u540E\u53F0",
|
|
@@ -5562,8 +5292,7 @@ var HtmxAdminPlugin = class {
|
|
|
5562
5292
|
homePath: options?.homePath || "",
|
|
5563
5293
|
navigation: options?.navigation ?? [],
|
|
5564
5294
|
authProvider: options?.authProvider,
|
|
5565
|
-
pages: options?.pages ?? []
|
|
5566
|
-
components: options?.components ?? []
|
|
5295
|
+
pages: options?.pages ?? []
|
|
5567
5296
|
};
|
|
5568
5297
|
this.initPages();
|
|
5569
5298
|
}
|
|
@@ -5595,11 +5324,6 @@ var HtmxAdminPlugin = class {
|
|
|
5595
5324
|
logger.info(
|
|
5596
5325
|
`HtmxAdminPlugin initialized${this.serviceName ? ` (service: ${this.serviceName})` : ""}`
|
|
5597
5326
|
);
|
|
5598
|
-
this.componentHandler = new HtmxComponentHandler(
|
|
5599
|
-
this.hono,
|
|
5600
|
-
this.options.prefix,
|
|
5601
|
-
this.options.components
|
|
5602
|
-
);
|
|
5603
5327
|
initializeCdnCache().catch((error) => {
|
|
5604
5328
|
logger.error("[HtmxAdminPlugin] CDN \u7F13\u5B58\u521D\u59CB\u5316\u5931\u8D25", error);
|
|
5605
5329
|
});
|
|
@@ -5621,4 +5345,4 @@ var HtmxAdminPlugin = class {
|
|
|
5621
5345
|
}
|
|
5622
5346
|
};
|
|
5623
5347
|
|
|
5624
|
-
export { BaseFeature,
|
|
5348
|
+
export { BaseFeature, BaseFormFeature, Breadcrumb, Button, Card, CustomFeature, DefaultCreateFeature, DefaultDeleteFeature, DefaultDetailFeature, DefaultEditFeature, DefaultListFeature, Dialog, EmptyState, ErrorAlert, FilterForm, Header, HtmxAdminPlugin, LoadingBar, ObjectEditor, PageModel, Pagination, PermissionDeniedContent, PermissionDeniedPage, SortableList, StringArrayEditor, Table, TagsEditor, checkUserPermission, getUserInfo, modelNameToPath, parseListParams };
|