@almadar/ui 5.161.0 → 5.163.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/avl/index.cjs +231 -72
- package/dist/avl/index.js +231 -72
- package/dist/components/index.cjs +233 -72
- package/dist/components/index.d.cts +26 -7
- package/dist/components/index.d.ts +26 -7
- package/dist/components/index.js +233 -72
- package/dist/hooks/index.cjs +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/locales/index.cjs +6 -0
- package/dist/locales/index.js +6 -0
- package/dist/providers/index.cjs +231 -72
- package/dist/providers/index.js +231 -72
- package/dist/runtime/index.cjs +231 -72
- package/dist/runtime/index.js +231 -72
- package/locales/ar.json +8 -6
- package/locales/en.json +3 -1
- package/locales/sl.json +3 -1
- package/package.json +4 -4
|
@@ -34180,6 +34180,33 @@ var init_Lightbox = __esm({
|
|
|
34180
34180
|
exports.Lightbox.displayName = "Lightbox";
|
|
34181
34181
|
}
|
|
34182
34182
|
});
|
|
34183
|
+
|
|
34184
|
+
// lib/relationLabel.ts
|
|
34185
|
+
function relationLabel(value) {
|
|
34186
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date)
|
|
34187
|
+
return null;
|
|
34188
|
+
for (const key of ["name", "title", "label"]) {
|
|
34189
|
+
const candidate = value[key];
|
|
34190
|
+
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
34191
|
+
}
|
|
34192
|
+
const id = value.id;
|
|
34193
|
+
return id !== void 0 && id !== null ? String(id) : null;
|
|
34194
|
+
}
|
|
34195
|
+
function relationDisplayLabels(value, options) {
|
|
34196
|
+
if (value === void 0 || value === null || value === "") return [];
|
|
34197
|
+
if (Array.isArray(value)) {
|
|
34198
|
+
return value.flatMap((item) => relationDisplayLabels(item, options));
|
|
34199
|
+
}
|
|
34200
|
+
const hydrated = relationLabel(value);
|
|
34201
|
+
if (hydrated !== null) return [hydrated];
|
|
34202
|
+
const raw = String(value);
|
|
34203
|
+
const match = options?.find((opt) => opt.value === raw);
|
|
34204
|
+
return [match ? match.label : raw];
|
|
34205
|
+
}
|
|
34206
|
+
var init_relationLabel = __esm({
|
|
34207
|
+
"lib/relationLabel.ts"() {
|
|
34208
|
+
}
|
|
34209
|
+
});
|
|
34183
34210
|
function renderIconInput3(icon, props) {
|
|
34184
34211
|
return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, ...props });
|
|
34185
34212
|
}
|
|
@@ -34497,6 +34524,7 @@ var init_TableView = __esm({
|
|
|
34497
34524
|
"use client";
|
|
34498
34525
|
init_cn();
|
|
34499
34526
|
init_format();
|
|
34527
|
+
init_relationLabel();
|
|
34500
34528
|
init_getNestedValue();
|
|
34501
34529
|
init_useEventBus();
|
|
34502
34530
|
init_Box();
|
|
@@ -34510,7 +34538,13 @@ var init_TableView = __esm({
|
|
|
34510
34538
|
init_Menu();
|
|
34511
34539
|
init_useDataDnd();
|
|
34512
34540
|
tableViewLog = logger.createLogger("almadar:ui:table-view");
|
|
34513
|
-
formatCell = (value, format) =>
|
|
34541
|
+
formatCell = (value, format) => {
|
|
34542
|
+
if (value !== null && value !== void 0 && typeof value === "object" && !(value instanceof Date)) {
|
|
34543
|
+
const labels = relationDisplayLabels(value);
|
|
34544
|
+
if (labels.length > 0) return labels.join(", ");
|
|
34545
|
+
}
|
|
34546
|
+
return formatValue(value, format);
|
|
34547
|
+
};
|
|
34514
34548
|
MAX_MEASURED_COL_CH = 32;
|
|
34515
34549
|
BADGE_CHROME_CH = 4;
|
|
34516
34550
|
alignClass = {
|
|
@@ -38125,6 +38159,13 @@ var init_RichTextEditor = __esm({
|
|
|
38125
38159
|
document.execCommand("createLink", false, safe);
|
|
38126
38160
|
afterEdit();
|
|
38127
38161
|
}, [afterEdit, t, toolbar.link]);
|
|
38162
|
+
const execImage = React77.useCallback(() => {
|
|
38163
|
+
const url = window.prompt(t("richTextEditor.imagePrompt"));
|
|
38164
|
+
if (!url) return;
|
|
38165
|
+
const safe = safeUrl(url, ["http://", "https://", "data:image/"]) ?? `https://${url}`;
|
|
38166
|
+
document.execCommand("insertImage", false, safe);
|
|
38167
|
+
afterEdit();
|
|
38168
|
+
}, [afterEdit, t]);
|
|
38128
38169
|
const execRule = React77.useCallback(() => {
|
|
38129
38170
|
document.execCommand("insertHorizontalRule", false);
|
|
38130
38171
|
afterEdit();
|
|
@@ -38162,6 +38203,7 @@ var init_RichTextEditor = __esm({
|
|
|
38162
38203
|
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Quote, label: t("richTextEditor.quote"), active: toolbar.block === "blockquote", onExec: () => execBlock("blockquote") }),
|
|
38163
38204
|
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Code, label: t("richTextEditor.code"), active: toolbar.block === "pre", onExec: () => execBlock("pre") }),
|
|
38164
38205
|
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Link, label: toolbar.link ? t("richTextEditor.removeLink") : t("richTextEditor.link"), active: toolbar.link, onExec: execLink }),
|
|
38206
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Image, label: t("richTextEditor.image"), onExec: execImage }),
|
|
38165
38207
|
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Minus, label: t("richTextEditor.divider"), onExec: execRule })
|
|
38166
38208
|
]
|
|
38167
38209
|
}
|
|
@@ -38199,9 +38241,11 @@ function renderIconInput4(icon, props) {
|
|
|
38199
38241
|
return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, ...props });
|
|
38200
38242
|
}
|
|
38201
38243
|
function DocumentPanel({
|
|
38202
|
-
|
|
38244
|
+
id,
|
|
38203
38245
|
title,
|
|
38204
38246
|
subtitle,
|
|
38247
|
+
coverImage,
|
|
38248
|
+
icon,
|
|
38205
38249
|
value,
|
|
38206
38250
|
actions,
|
|
38207
38251
|
maxInlineActions,
|
|
@@ -38219,14 +38263,14 @@ function DocumentPanel({
|
|
|
38219
38263
|
const eventBus = useEventBus();
|
|
38220
38264
|
const { t } = hooks.useTranslate();
|
|
38221
38265
|
const [titleDraft, setTitleDraft] = React77.useState(null);
|
|
38222
|
-
const recordId =
|
|
38266
|
+
const recordId = id ?? "";
|
|
38223
38267
|
const actionDefs = actions ?? [];
|
|
38224
38268
|
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
38225
38269
|
const inlineActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
38226
38270
|
const menuActions = actionDefs.filter((a) => !inlineActions.includes(a));
|
|
38227
38271
|
const fireAction = (action) => {
|
|
38228
38272
|
if (!action.event) return;
|
|
38229
|
-
eventBus.emit(`UI:${action.event}`, { id: recordId,
|
|
38273
|
+
eventBus.emit(`UI:${action.event}`, { id: recordId, title: title ?? "" });
|
|
38230
38274
|
};
|
|
38231
38275
|
const commitTitle = () => {
|
|
38232
38276
|
if (!titleCommitEvent) return;
|
|
@@ -38277,62 +38321,74 @@ function DocumentPanel({
|
|
|
38277
38321
|
const emitWithId = (event) => () => {
|
|
38278
38322
|
if (event) eventBus.emit(`UI:${event}`, { id: recordId });
|
|
38279
38323
|
};
|
|
38280
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
38281
|
-
/* @__PURE__ */ jsxRuntime.
|
|
38282
|
-
|
|
38283
|
-
titleNode,
|
|
38284
|
-
subtitle ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "secondary", children: subtitle }) : null
|
|
38285
|
-
] }),
|
|
38286
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", className: "flex-shrink-0 pt-1 items-center", children: editing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
38287
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "muted", className: "hidden sm:block", children: autosaveHint ?? (t("documentPanel.autosaveHint") || "") }),
|
|
38288
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "primary", size: "sm", onClick: emitWithId(doneEvent), "data-testid": "document-done", children: doneLabel ?? (t("documentPanel.done") || "Done") })
|
|
38289
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
38290
|
-
editEvent && /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "ghost", size: "sm", onClick: emitWithId(editEvent), "data-testid": "document-edit", children: [
|
|
38291
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "edit", size: "xs", className: "mr-1" }),
|
|
38292
|
-
editLabel ?? (t("documentPanel.edit") || "Edit")
|
|
38293
|
-
] }),
|
|
38294
|
-
inlineActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
38295
|
-
exports.Button,
|
|
38296
|
-
{
|
|
38297
|
-
variant: "primary",
|
|
38298
|
-
size: "sm",
|
|
38299
|
-
onClick: () => fireAction(action),
|
|
38300
|
-
"data-testid": `action-${action.event}`,
|
|
38301
|
-
children: [
|
|
38302
|
-
action.icon && renderIconInput4(action.icon, { size: "xs", className: "mr-1" }),
|
|
38303
|
-
action.label
|
|
38304
|
-
]
|
|
38305
|
-
},
|
|
38306
|
-
idx
|
|
38307
|
-
)),
|
|
38308
|
-
menuActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
38309
|
-
exports.Menu,
|
|
38310
|
-
{
|
|
38311
|
-
position: "bottom-end",
|
|
38312
|
-
trigger: /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
38313
|
-
items: menuActions.map((action) => ({
|
|
38314
|
-
label: action.label,
|
|
38315
|
-
icon: action.icon,
|
|
38316
|
-
variant: action.variant === "danger" ? "danger" : "default",
|
|
38317
|
-
onClick: () => fireAction(action)
|
|
38318
|
-
}))
|
|
38319
|
-
}
|
|
38320
|
-
)
|
|
38321
|
-
] }) })
|
|
38322
|
-
] }),
|
|
38323
|
-
editing ? /* @__PURE__ */ jsxRuntime.jsx(exports.RichTextEditor, { value, changeEvent: contentChangeEvent, placeholder }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
38324
|
-
exports.Box,
|
|
38324
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(exports.Card, { variant: "elevated", className: cn("w-full overflow-hidden", className), children: [
|
|
38325
|
+
coverImage ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "h-44 w-full sm:h-52", "data-testid": "document-cover", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
38326
|
+
"img",
|
|
38325
38327
|
{
|
|
38326
|
-
|
|
38327
|
-
|
|
38328
|
-
|
|
38329
|
-
|
|
38330
|
-
|
|
38331
|
-
|
|
38332
|
-
|
|
38333
|
-
|
|
38334
|
-
|
|
38335
|
-
|
|
38328
|
+
src: coverImage,
|
|
38329
|
+
alt: "",
|
|
38330
|
+
"aria-hidden": "true",
|
|
38331
|
+
className: "h-full w-full object-cover"
|
|
38332
|
+
}
|
|
38333
|
+
) }) : null,
|
|
38334
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", className: "p-6 sm:p-8", children: [
|
|
38335
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", className: "justify-between items-start", children: [
|
|
38336
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
38337
|
+
icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-muted-foreground", "data-testid": "document-icon", children: renderIconInput4(icon, { size: "lg" }) }) : null,
|
|
38338
|
+
titleNode,
|
|
38339
|
+
subtitle ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "secondary", children: subtitle }) : null
|
|
38340
|
+
] }),
|
|
38341
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", className: "flex-shrink-0 pt-1 items-center", children: editing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
38342
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "muted", className: "hidden sm:block", children: autosaveHint ?? (t("documentPanel.autosaveHint") || "") }),
|
|
38343
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "primary", size: "sm", onClick: emitWithId(doneEvent), "data-testid": "document-done", children: doneLabel ?? (t("documentPanel.done") || "Done") })
|
|
38344
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
38345
|
+
editEvent && /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "ghost", size: "sm", onClick: emitWithId(editEvent), "data-testid": "document-edit", children: [
|
|
38346
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "edit", size: "xs", className: "mr-1" }),
|
|
38347
|
+
editLabel ?? (t("documentPanel.edit") || "Edit")
|
|
38348
|
+
] }),
|
|
38349
|
+
inlineActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
38350
|
+
exports.Button,
|
|
38351
|
+
{
|
|
38352
|
+
variant: "primary",
|
|
38353
|
+
size: "sm",
|
|
38354
|
+
onClick: () => fireAction(action),
|
|
38355
|
+
"data-testid": `action-${action.event}`,
|
|
38356
|
+
children: [
|
|
38357
|
+
action.icon && renderIconInput4(action.icon, { size: "xs", className: "mr-1" }),
|
|
38358
|
+
action.label
|
|
38359
|
+
]
|
|
38360
|
+
},
|
|
38361
|
+
idx
|
|
38362
|
+
)),
|
|
38363
|
+
menuActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
38364
|
+
exports.Menu,
|
|
38365
|
+
{
|
|
38366
|
+
position: "bottom-end",
|
|
38367
|
+
trigger: /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
38368
|
+
items: menuActions.map((action) => ({
|
|
38369
|
+
label: action.label,
|
|
38370
|
+
icon: action.icon,
|
|
38371
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
38372
|
+
onClick: () => fireAction(action)
|
|
38373
|
+
}))
|
|
38374
|
+
}
|
|
38375
|
+
)
|
|
38376
|
+
] }) })
|
|
38377
|
+
] }),
|
|
38378
|
+
editing ? /* @__PURE__ */ jsxRuntime.jsx(exports.RichTextEditor, { value, changeEvent: contentChangeEvent, placeholder }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
38379
|
+
exports.Box,
|
|
38380
|
+
{
|
|
38381
|
+
onClick: emitWithId(editEvent),
|
|
38382
|
+
className: cn(
|
|
38383
|
+
"rounded-md px-1 -mx-1 min-h-[16rem]",
|
|
38384
|
+
editEvent && "cursor-text transition-colors hover:bg-muted/30"
|
|
38385
|
+
),
|
|
38386
|
+
"data-testid": "document-body",
|
|
38387
|
+
children: value && value !== "" ? /* @__PURE__ */ jsxRuntime.jsx(exports.RichTextEditor, { value, readOnly: true }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "muted", children: placeholder ?? (t("documentPanel.placeholder") || "") })
|
|
38388
|
+
}
|
|
38389
|
+
)
|
|
38390
|
+
] })
|
|
38391
|
+
] });
|
|
38336
38392
|
}
|
|
38337
38393
|
var init_DocumentPanel = __esm({
|
|
38338
38394
|
"components/core/molecules/DocumentPanel.tsx"() {
|
|
@@ -38356,17 +38412,16 @@ function renderIconInput5(icon, props) {
|
|
|
38356
38412
|
function fieldName(field) {
|
|
38357
38413
|
return field.name ?? field.key ?? "";
|
|
38358
38414
|
}
|
|
38359
|
-
function
|
|
38360
|
-
if (value
|
|
38361
|
-
|
|
38362
|
-
|
|
38363
|
-
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
38415
|
+
function relationId(value) {
|
|
38416
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date)) {
|
|
38417
|
+
const id = value.id;
|
|
38418
|
+
if (id !== void 0 && id !== null) return String(id);
|
|
38364
38419
|
}
|
|
38365
|
-
|
|
38366
|
-
return id !== void 0 && id !== null ? String(id) : null;
|
|
38420
|
+
return String(value);
|
|
38367
38421
|
}
|
|
38368
38422
|
function fieldKind(field, value) {
|
|
38369
38423
|
if (field.kind) return field.kind;
|
|
38424
|
+
if (field.type === "image") return "image";
|
|
38370
38425
|
if (field.options && field.options.length > 0) return "select";
|
|
38371
38426
|
if (typeof value === "boolean" || field.format === "boolean") return "boolean";
|
|
38372
38427
|
if (Array.isArray(value) || relationLabel(value ?? null) !== null) return "readonly";
|
|
@@ -38376,6 +38431,7 @@ function DocumentDetails({
|
|
|
38376
38431
|
entity,
|
|
38377
38432
|
fields,
|
|
38378
38433
|
metaCommitEvent,
|
|
38434
|
+
relationEvent,
|
|
38379
38435
|
title,
|
|
38380
38436
|
className
|
|
38381
38437
|
}) {
|
|
@@ -38390,11 +38446,51 @@ function DocumentDetails({
|
|
|
38390
38446
|
if (!metaCommitEvent || next === current) return;
|
|
38391
38447
|
eventBus.emit(`UI:${metaCommitEvent}`, { id: recordId, patch: { id: recordId, [name]: next } });
|
|
38392
38448
|
};
|
|
38449
|
+
const relationChip = (item, name, key) => {
|
|
38450
|
+
const label = relationLabel(item) ?? humanizeEnumValue(String(item));
|
|
38451
|
+
if (!relationEvent) {
|
|
38452
|
+
return /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: "default", children: label }, key);
|
|
38453
|
+
}
|
|
38454
|
+
const emitClick = () => eventBus.emit(`UI:${relationEvent}`, { field: name, id: relationId(item), name: label });
|
|
38455
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
38456
|
+
exports.Badge,
|
|
38457
|
+
{
|
|
38458
|
+
variant: "default",
|
|
38459
|
+
role: "button",
|
|
38460
|
+
tabIndex: 0,
|
|
38461
|
+
className: "cursor-pointer transition-colors hover:bg-accent",
|
|
38462
|
+
onClick: emitClick,
|
|
38463
|
+
onKeyDown: (e) => {
|
|
38464
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
38465
|
+
e.preventDefault();
|
|
38466
|
+
emitClick();
|
|
38467
|
+
}
|
|
38468
|
+
},
|
|
38469
|
+
"data-testid": `relation-chip-${name}`,
|
|
38470
|
+
children: label
|
|
38471
|
+
},
|
|
38472
|
+
key
|
|
38473
|
+
);
|
|
38474
|
+
};
|
|
38393
38475
|
const renderValue = (field) => {
|
|
38394
38476
|
const name = fieldName(field);
|
|
38395
38477
|
const raw = getNestedValue(entity ?? {}, name);
|
|
38396
38478
|
const kind = fieldKind(field, raw);
|
|
38397
38479
|
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
38480
|
+
if (kind === "image") {
|
|
38481
|
+
const url = typeof raw === "string" ? raw : "";
|
|
38482
|
+
if (!url) return /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "secondary", children: "\u2014" });
|
|
38483
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
38484
|
+
"img",
|
|
38485
|
+
{
|
|
38486
|
+
src: url,
|
|
38487
|
+
alt: label,
|
|
38488
|
+
loading: "lazy",
|
|
38489
|
+
className: "max-h-32 w-full rounded-md border border-border object-cover",
|
|
38490
|
+
"data-testid": `document-property-image-${name}`
|
|
38491
|
+
}
|
|
38492
|
+
);
|
|
38493
|
+
}
|
|
38398
38494
|
if (kind === "boolean") {
|
|
38399
38495
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
38400
38496
|
exports.Switch,
|
|
@@ -38424,9 +38520,12 @@ function DocumentDetails({
|
|
|
38424
38520
|
if (raw.length === 0) {
|
|
38425
38521
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "secondary", children: "\u2014" });
|
|
38426
38522
|
}
|
|
38427
|
-
return /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", className: "flex-wrap", children: raw.map((item, i) =>
|
|
38523
|
+
return /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", className: "flex-wrap", children: raw.map((item, i) => relationChip(item, name, i)) });
|
|
38524
|
+
}
|
|
38525
|
+
if (raw !== void 0 && raw !== null && raw !== "" && relationLabel(raw) !== null) {
|
|
38526
|
+
return relationChip(raw, name);
|
|
38428
38527
|
}
|
|
38429
|
-
const shown2 = raw === void 0 || raw === null || raw === "" ? "\u2014" :
|
|
38528
|
+
const shown2 = raw === void 0 || raw === null || raw === "" ? "\u2014" : formatValue(raw, field.format);
|
|
38430
38529
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "break-words", children: shown2 });
|
|
38431
38530
|
}
|
|
38432
38531
|
if (fieldDraft?.name === name) {
|
|
@@ -38495,6 +38594,7 @@ var init_DocumentDetails = __esm({
|
|
|
38495
38594
|
init_cn();
|
|
38496
38595
|
init_format();
|
|
38497
38596
|
init_getNestedValue();
|
|
38597
|
+
init_relationLabel();
|
|
38498
38598
|
init_useEventBus();
|
|
38499
38599
|
init_Box();
|
|
38500
38600
|
init_Stack();
|
|
@@ -43716,7 +43816,18 @@ function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
|
43716
43816
|
if (value === void 0 || value === null) return "\u2014";
|
|
43717
43817
|
const str2 = String(value);
|
|
43718
43818
|
switch (fieldType) {
|
|
43719
|
-
case "image":
|
|
43819
|
+
case "image": {
|
|
43820
|
+
if (!str2) return "\u2014";
|
|
43821
|
+
return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
43822
|
+
"img",
|
|
43823
|
+
{
|
|
43824
|
+
src: str2,
|
|
43825
|
+
alt: formatFieldLabel(fieldName2),
|
|
43826
|
+
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
43827
|
+
loading: "lazy"
|
|
43828
|
+
}
|
|
43829
|
+
) });
|
|
43830
|
+
}
|
|
43720
43831
|
case "url": {
|
|
43721
43832
|
if (str2.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str2.startsWith("data:image/")) {
|
|
43722
43833
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -43729,7 +43840,7 @@ function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
|
43729
43840
|
}
|
|
43730
43841
|
) });
|
|
43731
43842
|
}
|
|
43732
|
-
if (
|
|
43843
|
+
if (/^https?:\/\//i.test(str2)) {
|
|
43733
43844
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43734
43845
|
"a",
|
|
43735
43846
|
{
|
|
@@ -43815,8 +43926,10 @@ function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
|
43815
43926
|
return str2;
|
|
43816
43927
|
}
|
|
43817
43928
|
case "relation": {
|
|
43818
|
-
const
|
|
43819
|
-
|
|
43929
|
+
const labels = relationDisplayLabels(value, meta?.options);
|
|
43930
|
+
if (labels.length === 0) return "\u2014";
|
|
43931
|
+
if (labels.length === 1) return labels[0];
|
|
43932
|
+
return /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", wrap: true, children: labels.map((label, i) => /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: "default", children: label }, i)) });
|
|
43820
43933
|
}
|
|
43821
43934
|
case "file": {
|
|
43822
43935
|
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
@@ -43918,6 +44031,7 @@ var init_DetailPanel = __esm({
|
|
|
43918
44031
|
init_cn();
|
|
43919
44032
|
init_format();
|
|
43920
44033
|
init_getNestedValue();
|
|
44034
|
+
init_relationLabel();
|
|
43921
44035
|
init_useEventBus();
|
|
43922
44036
|
init_UploadDropZone();
|
|
43923
44037
|
formatFieldLabel = humanizeFieldName;
|
|
@@ -44576,6 +44690,8 @@ function determineInputType(field) {
|
|
|
44576
44690
|
return "url";
|
|
44577
44691
|
case "file":
|
|
44578
44692
|
return "file";
|
|
44693
|
+
case "image":
|
|
44694
|
+
return "image";
|
|
44579
44695
|
case "money":
|
|
44580
44696
|
return "currency";
|
|
44581
44697
|
case "number":
|
|
@@ -45175,6 +45291,49 @@ var init_Form = __esm({
|
|
|
45175
45291
|
}
|
|
45176
45292
|
}
|
|
45177
45293
|
);
|
|
45294
|
+
case "image": {
|
|
45295
|
+
const imageUrl = typeof currentValue2 === "string" ? currentValue2 : "";
|
|
45296
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", children: [
|
|
45297
|
+
imageUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
45298
|
+
"img",
|
|
45299
|
+
{
|
|
45300
|
+
src: imageUrl,
|
|
45301
|
+
alt: "",
|
|
45302
|
+
"aria-hidden": "true",
|
|
45303
|
+
className: "h-24 w-full max-w-xs rounded-md border border-border object-cover",
|
|
45304
|
+
"data-testid": `image-preview-${fieldName2}`
|
|
45305
|
+
}
|
|
45306
|
+
) : null,
|
|
45307
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45308
|
+
exports.Input,
|
|
45309
|
+
{
|
|
45310
|
+
...commonProps,
|
|
45311
|
+
type: "url",
|
|
45312
|
+
value: imageUrl,
|
|
45313
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
45314
|
+
}
|
|
45315
|
+
),
|
|
45316
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45317
|
+
exports.UploadDropZone,
|
|
45318
|
+
{
|
|
45319
|
+
accept: "image/*",
|
|
45320
|
+
maxFiles: 1,
|
|
45321
|
+
maxSize: 2 * 1024 * 1024,
|
|
45322
|
+
disabled: isLoading,
|
|
45323
|
+
onFiles: (files) => {
|
|
45324
|
+
const f3 = files[0];
|
|
45325
|
+
if (!f3) return;
|
|
45326
|
+
const reader = new FileReader();
|
|
45327
|
+
reader.onload = () => handleChange(
|
|
45328
|
+
fieldName2,
|
|
45329
|
+
typeof reader.result === "string" ? reader.result : ""
|
|
45330
|
+
);
|
|
45331
|
+
reader.readAsDataURL(f3);
|
|
45332
|
+
}
|
|
45333
|
+
}
|
|
45334
|
+
)
|
|
45335
|
+
] });
|
|
45336
|
+
}
|
|
45178
45337
|
case "date":
|
|
45179
45338
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45180
45339
|
exports.Input,
|
|
@@ -53941,6 +54100,8 @@ var en_default = {
|
|
|
53941
54100
|
"richTextEditor.removeLink": "Remove link",
|
|
53942
54101
|
"richTextEditor.divider": "Divider",
|
|
53943
54102
|
"richTextEditor.linkPrompt": "Link address",
|
|
54103
|
+
"richTextEditor.image": "Insert image",
|
|
54104
|
+
"richTextEditor.imagePrompt": "Image URL",
|
|
53944
54105
|
"richTextEditor.placeholder": "Start writing\u2026"
|
|
53945
54106
|
};
|
|
53946
54107
|
|
|
@@ -8875,12 +8875,18 @@ interface DocumentPanelAction {
|
|
|
8875
8875
|
* @capabilities document page, note editor, wiki page, article editor, writing surface, rich text document, content editing canvas
|
|
8876
8876
|
*/
|
|
8877
8877
|
interface DocumentPanelProps {
|
|
8878
|
-
/** The
|
|
8879
|
-
|
|
8878
|
+
/** The record's id — carried on every commit and action event. */
|
|
8879
|
+
id?: string;
|
|
8880
8880
|
/** Document title (falls back to "Untitled" for a blank draft) */
|
|
8881
8881
|
title?: string;
|
|
8882
8882
|
/** Muted byline under the title; hidden when empty */
|
|
8883
8883
|
subtitle?: string;
|
|
8884
|
+
/** Cover/hero image URL painted as a full-bleed banner above the header
|
|
8885
|
+
* row (Notion/article-hero shape); hidden when empty */
|
|
8886
|
+
coverImage?: string;
|
|
8887
|
+
/** Document icon rendered beside the title (a file glyph, a domain icon);
|
|
8888
|
+
* hidden when empty */
|
|
8889
|
+
icon?: IconInput;
|
|
8884
8890
|
/** The document body as rich-text HTML */
|
|
8885
8891
|
value?: string;
|
|
8886
8892
|
/** Header actions (settings, history, …). At most one explicit primary
|
|
@@ -8916,7 +8922,7 @@ interface DocumentPanelProps {
|
|
|
8916
8922
|
placeholder?: string;
|
|
8917
8923
|
className?: string;
|
|
8918
8924
|
}
|
|
8919
|
-
declare function DocumentPanel({
|
|
8925
|
+
declare function DocumentPanel({ id, title, subtitle, coverImage, icon, value, actions, maxInlineActions, editing, titleCommitEvent, contentChangeEvent, editEvent, doneEvent, editLabel, doneLabel, autosaveHint, placeholder, className, }: DocumentPanelProps): React__default.ReactElement;
|
|
8920
8926
|
|
|
8921
8927
|
/**
|
|
8922
8928
|
* DocumentDetails Molecule
|
|
@@ -8945,19 +8951,24 @@ interface DocumentDetailsField {
|
|
|
8945
8951
|
header?: string;
|
|
8946
8952
|
/** Lucide icon name or component shown beside the label */
|
|
8947
8953
|
icon?: IconInput;
|
|
8948
|
-
/** How the property edits: text input, boolean switch, select,
|
|
8949
|
-
* Inferred from the value when omitted
|
|
8950
|
-
|
|
8954
|
+
/** How the property edits: text input, boolean switch, select, image
|
|
8955
|
+
* thumbnail, or display-only. Inferred from the value when omitted
|
|
8956
|
+
* (boolean → boolean, array → readonly, image-typed → image, else text). */
|
|
8957
|
+
kind?: 'text' | 'boolean' | 'select' | 'readonly' | 'image';
|
|
8951
8958
|
/** Options for kind: 'select' */
|
|
8952
8959
|
options?: readonly string[];
|
|
8953
8960
|
/** Display format for the read value */
|
|
8954
8961
|
format?: 'date' | 'currency' | 'number' | 'boolean' | 'percent';
|
|
8962
|
+
/** Entity-declared field type, injected by the display fields contract —
|
|
8963
|
+
* drives kind inference (e.g. `image` → thumbnail row). */
|
|
8964
|
+
type?: string;
|
|
8955
8965
|
}
|
|
8956
8966
|
/**
|
|
8957
8967
|
* DocumentDetails — the document's metadata as a compact settings card for
|
|
8958
8968
|
* the rail beside a DocumentPanel, each property committing in place.
|
|
8959
8969
|
*
|
|
8960
8970
|
* @capabilities document settings, page details, post settings sidebar, metadata panel, document properties, publish settings
|
|
8971
|
+
* @fieldsContract display
|
|
8961
8972
|
*/
|
|
8962
8973
|
interface DocumentDetailsProps {
|
|
8963
8974
|
/** The loaded record — supplies the id every commit carries and the
|
|
@@ -8971,11 +8982,19 @@ interface DocumentDetailsProps {
|
|
|
8971
8982
|
id: string;
|
|
8972
8983
|
patch: Record<string, FieldValue>;
|
|
8973
8984
|
}>;
|
|
8985
|
+
/** Makes relation chips clickable: emitted with { field, id, name } when a
|
|
8986
|
+
* hydrated relation value (or one row of a many-relation) is clicked —
|
|
8987
|
+
* the host routes it to the linked record's own surface. */
|
|
8988
|
+
relationEvent?: EventEmit<{
|
|
8989
|
+
field: string;
|
|
8990
|
+
id: string;
|
|
8991
|
+
name: string;
|
|
8992
|
+
}>;
|
|
8974
8993
|
/** Card heading (defaults to the localized "Details") */
|
|
8975
8994
|
title?: string;
|
|
8976
8995
|
className?: string;
|
|
8977
8996
|
}
|
|
8978
|
-
declare function DocumentDetails({ entity, fields, metaCommitEvent, title, className, }: DocumentDetailsProps): React__default.ReactElement | null;
|
|
8997
|
+
declare function DocumentDetails({ entity, fields, metaCommitEvent, relationEvent, title, className, }: DocumentDetailsProps): React__default.ReactElement | null;
|
|
8979
8998
|
|
|
8980
8999
|
/**
|
|
8981
9000
|
* ReplyTree Organism Component
|
|
@@ -8875,12 +8875,18 @@ interface DocumentPanelAction {
|
|
|
8875
8875
|
* @capabilities document page, note editor, wiki page, article editor, writing surface, rich text document, content editing canvas
|
|
8876
8876
|
*/
|
|
8877
8877
|
interface DocumentPanelProps {
|
|
8878
|
-
/** The
|
|
8879
|
-
|
|
8878
|
+
/** The record's id — carried on every commit and action event. */
|
|
8879
|
+
id?: string;
|
|
8880
8880
|
/** Document title (falls back to "Untitled" for a blank draft) */
|
|
8881
8881
|
title?: string;
|
|
8882
8882
|
/** Muted byline under the title; hidden when empty */
|
|
8883
8883
|
subtitle?: string;
|
|
8884
|
+
/** Cover/hero image URL painted as a full-bleed banner above the header
|
|
8885
|
+
* row (Notion/article-hero shape); hidden when empty */
|
|
8886
|
+
coverImage?: string;
|
|
8887
|
+
/** Document icon rendered beside the title (a file glyph, a domain icon);
|
|
8888
|
+
* hidden when empty */
|
|
8889
|
+
icon?: IconInput;
|
|
8884
8890
|
/** The document body as rich-text HTML */
|
|
8885
8891
|
value?: string;
|
|
8886
8892
|
/** Header actions (settings, history, …). At most one explicit primary
|
|
@@ -8916,7 +8922,7 @@ interface DocumentPanelProps {
|
|
|
8916
8922
|
placeholder?: string;
|
|
8917
8923
|
className?: string;
|
|
8918
8924
|
}
|
|
8919
|
-
declare function DocumentPanel({
|
|
8925
|
+
declare function DocumentPanel({ id, title, subtitle, coverImage, icon, value, actions, maxInlineActions, editing, titleCommitEvent, contentChangeEvent, editEvent, doneEvent, editLabel, doneLabel, autosaveHint, placeholder, className, }: DocumentPanelProps): React__default.ReactElement;
|
|
8920
8926
|
|
|
8921
8927
|
/**
|
|
8922
8928
|
* DocumentDetails Molecule
|
|
@@ -8945,19 +8951,24 @@ interface DocumentDetailsField {
|
|
|
8945
8951
|
header?: string;
|
|
8946
8952
|
/** Lucide icon name or component shown beside the label */
|
|
8947
8953
|
icon?: IconInput;
|
|
8948
|
-
/** How the property edits: text input, boolean switch, select,
|
|
8949
|
-
* Inferred from the value when omitted
|
|
8950
|
-
|
|
8954
|
+
/** How the property edits: text input, boolean switch, select, image
|
|
8955
|
+
* thumbnail, or display-only. Inferred from the value when omitted
|
|
8956
|
+
* (boolean → boolean, array → readonly, image-typed → image, else text). */
|
|
8957
|
+
kind?: 'text' | 'boolean' | 'select' | 'readonly' | 'image';
|
|
8951
8958
|
/** Options for kind: 'select' */
|
|
8952
8959
|
options?: readonly string[];
|
|
8953
8960
|
/** Display format for the read value */
|
|
8954
8961
|
format?: 'date' | 'currency' | 'number' | 'boolean' | 'percent';
|
|
8962
|
+
/** Entity-declared field type, injected by the display fields contract —
|
|
8963
|
+
* drives kind inference (e.g. `image` → thumbnail row). */
|
|
8964
|
+
type?: string;
|
|
8955
8965
|
}
|
|
8956
8966
|
/**
|
|
8957
8967
|
* DocumentDetails — the document's metadata as a compact settings card for
|
|
8958
8968
|
* the rail beside a DocumentPanel, each property committing in place.
|
|
8959
8969
|
*
|
|
8960
8970
|
* @capabilities document settings, page details, post settings sidebar, metadata panel, document properties, publish settings
|
|
8971
|
+
* @fieldsContract display
|
|
8961
8972
|
*/
|
|
8962
8973
|
interface DocumentDetailsProps {
|
|
8963
8974
|
/** The loaded record — supplies the id every commit carries and the
|
|
@@ -8971,11 +8982,19 @@ interface DocumentDetailsProps {
|
|
|
8971
8982
|
id: string;
|
|
8972
8983
|
patch: Record<string, FieldValue>;
|
|
8973
8984
|
}>;
|
|
8985
|
+
/** Makes relation chips clickable: emitted with { field, id, name } when a
|
|
8986
|
+
* hydrated relation value (or one row of a many-relation) is clicked —
|
|
8987
|
+
* the host routes it to the linked record's own surface. */
|
|
8988
|
+
relationEvent?: EventEmit<{
|
|
8989
|
+
field: string;
|
|
8990
|
+
id: string;
|
|
8991
|
+
name: string;
|
|
8992
|
+
}>;
|
|
8974
8993
|
/** Card heading (defaults to the localized "Details") */
|
|
8975
8994
|
title?: string;
|
|
8976
8995
|
className?: string;
|
|
8977
8996
|
}
|
|
8978
|
-
declare function DocumentDetails({ entity, fields, metaCommitEvent, title, className, }: DocumentDetailsProps): React__default.ReactElement | null;
|
|
8997
|
+
declare function DocumentDetails({ entity, fields, metaCommitEvent, relationEvent, title, className, }: DocumentDetailsProps): React__default.ReactElement | null;
|
|
8979
8998
|
|
|
8980
8999
|
/**
|
|
8981
9000
|
* ReplyTree Organism Component
|