fixed relation and file custom change event trigger

This commit is contained in:
Gani Georgiev
2026-04-19 08:52:40 +03:00
parent 5cc95a2e63
commit 6012ba701d
5 changed files with 204 additions and 203 deletions

File diff suppressed because one or more lines are too long

2
ui/dist/index.html vendored
View File

@@ -13,7 +13,7 @@
<!-- prism -->
<script src="./libs/prism/prism.js" data-manual></script>
<script type="module" crossorigin src="./assets/index-DhtJzO0I.js"></script>
<script type="module" crossorigin src="./assets/index-OxsdchXY.js"></script>
<link rel="modulepreload" crossorigin href="./assets/pocketbase.es-B_4DUNUU.js">
<link rel="stylesheet" crossorigin href="./assets/index-BLIFQr7L.css">
</head>

View File

@@ -4,8 +4,7 @@
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"format": "dprint fmt"
"build": "dprint fmt && vite build"
},
"dependencies": {
"leaflet": "^1.9.4",

View File

@@ -57,7 +57,7 @@ export function input(props) {
// trigger custom change event for clearing field errors
function triggerChangeEvent() {
fieldEl?.dispatchEvent(
fieldContentEl?.dispatchEvent(
new CustomEvent("change", {
detail: { data: props },
bubbles: true,
@@ -92,7 +92,6 @@ export function input(props) {
const fileInput = t.input({
type: "file",
hidden: true,
name: () => props.field.name,
multiple: () => props.field.maxSelect > 1,
accept: () => props.field.mimeTypes?.join(",") || undefined,
onchange: (e) => {
@@ -101,37 +100,11 @@ export function input(props) {
},
});
const fieldEl = t.div(
const fieldContentEl = t.output(
{
className: "record-field-input field-type-file",
ondragover: (e) => {
e.preventDefault(); // prevent default to allow drop
className: "field-content",
name: () => props.field.name,
},
ondrop: (e) => {
const files = e.dataTransfer?.files || [];
if (!files.length) {
return; // not a file drop
}
e.preventDefault();
if (local.maxReached) {
return;
}
addFiles(files);
},
},
t.div(
{ className: () => `field ${props.field.required ? "required" : ""}` },
t.label(
{ htmlFor: uniqueId },
t.i({ className: app.fieldTypes.file.icon, ariaHidden: true }),
t.span({ className: "txt" }, () => props.field.name),
),
fileInput,
t.div(
{ className: "field-content" },
// @todo enable ordering new files before/inbetween existing
app.components.sortable({
className: "list",
@@ -235,7 +208,7 @@ export function input(props) {
disabled: () => local.maxReached,
onclick: (e) => {
if (!local.maxReached) {
fileInput.click();
fileInput?.click();
}
document.activeElement?.blur();
},
@@ -243,7 +216,38 @@ export function input(props) {
t.i({ className: "ri-upload-cloud-line", ariaHidden: true }),
t.span({ className: "txt" }, "Upload or drop new file"),
),
);
return t.div(
{
className: "record-field-input field-type-file",
ondragover: (e) => {
e.preventDefault(); // prevent default to allow drop
},
ondrop: (e) => {
const files = e.dataTransfer?.files || [];
if (!files.length) {
return; // not a file drop
}
e.preventDefault();
if (local.maxReached) {
return;
}
addFiles(files);
},
},
t.div(
{ className: () => `field ${props.field.required ? "required" : ""}` },
t.label(
{ htmlFor: uniqueId },
t.i({ className: app.fieldTypes.file.icon, ariaHidden: true }),
t.span({ className: "txt" }, () => props.field.name),
),
fileInput,
fieldContentEl,
),
() => {
if (props.field.help) {
@@ -251,6 +255,4 @@ export function input(props) {
}
},
);
return fieldEl;
}

View File

@@ -9,7 +9,7 @@ export function input(props) {
// trigger custom change event for clearing field errors
function triggerChangeEvent() {
fieldEl?.dispatchEvent(
fieldContentEl?.dispatchEvent(
new CustomEvent("change", {
detail: { data: props },
bubbles: true,
@@ -87,6 +87,7 @@ export function input(props) {
function updateRecordValue(ids = []) {
props.record[props.field.name] = props.field.maxSelect > 1 ? ids : ids?.[0] || "";
triggerChangeEvent();
}
const watchers = [
@@ -96,21 +97,7 @@ export function input(props) {
),
];
const fieldEl = t.div(
{
className: "record-field-input field-type-relation",
onunmount: () => {
watchers.forEach((w) => w?.unwatch());
},
},
t.div(
{ className: () => `field ${props.field.required ? "required" : ""}` },
t.label(
{ htmlFor: uniqueId },
t.i({ className: app.fieldTypes.relation.icon, ariaHidden: true }),
t.span({ className: "txt" }, () => props.field.name),
),
t.output(
const fieldContentEl = t.output(
{
className: "field-content",
name: () => props.field.name,
@@ -136,7 +123,6 @@ export function input(props) {
onchange: (sortedList) => {
local.selected = sortedList;
updateRecordValue(sortedList.map((r) => r.id));
triggerChangeEvent();
},
dataItem: (record, relIndex) => {
return t.div(
@@ -184,7 +170,23 @@ export function input(props) {
t.i({ className: "ri-magic-line", ariaHidden: true }),
t.span({ className: "txt" }, "Open records picker"),
),
);
return t.div(
{
className: "record-field-input field-type-relation",
onunmount: () => {
watchers.forEach((w) => w?.unwatch());
},
},
t.div(
{ className: () => `field ${props.field.required ? "required" : ""}` },
t.label(
{ htmlFor: uniqueId },
t.i({ className: app.fieldTypes.relation.icon, ariaHidden: true }),
t.span({ className: "txt" }, () => props.field.name),
),
fieldContentEl,
),
() => {
if (props.field.help) {
@@ -192,6 +194,4 @@ export function input(props) {
}
},
);
return fieldEl;
}