diff --git a/apps/metadata-utils/src/types.ts b/apps/metadata-utils/src/types.ts
index c31dd39a4f..111f907ccc 100644
--- a/apps/metadata-utils/src/types.ts
+++ b/apps/metadata-utils/src/types.ts
@@ -91,6 +91,13 @@ export interface IFieldError {
message: string;
}
+export interface IFormLegendSection {
+ label: string;
+ domId: string;
+ isActive?: boolean;
+ errorCount?: number;
+}
+
export type columnId = string;
export type columnValue = string | number | boolean | columnValueObject;
diff --git a/apps/tailwind-components/assets/css/main.css b/apps/tailwind-components/assets/css/main.css
index 03a8436077..81f2ffc914 100644
--- a/apps/tailwind-components/assets/css/main.css
+++ b/apps/tailwind-components/assets/css/main.css
@@ -38,6 +38,7 @@
--color-orange-500: #E1B53E;
--color-red-200: #FCECEF;
--color-red-500: #E14F62;
+ --color-red-700: #AE2A3F;
--color-gradient1: #0062C6;
--color-gradient2: #0072E4;
@@ -79,6 +80,7 @@
--background-color-input: var(--color-white);
--background-color-input-checked: var(--color-yellow-500);
--background-color-table: var(--color-white);
+ --background-color-notification: var(--color-red-700);
--text-color-button-primary: var(--color-white);
@@ -129,6 +131,7 @@
--text-color-table-column-header: var(--color-gray-600);
--text-color-form-header: var(--color-blue-800);
--text-color-input-description: var(--color-blue-800);
+ --text-color-legend-error-count: var(--color-white);
--text-color-invalid: var(--color-red-500);
--text-color-valid: var(--color-green-800);
diff --git a/apps/tailwind-components/components/form/Fields.vue b/apps/tailwind-components/components/form/Fields.vue
index 55fcedc568..cf3c75cb70 100644
--- a/apps/tailwind-components/components/form/Fields.vue
+++ b/apps/tailwind-components/components/form/Fields.vue
@@ -101,13 +101,15 @@ defineExpose({ validate });
+
+
+
+
diff --git a/apps/tailwind-components/pages/Form.story.vue b/apps/tailwind-components/pages/Form.story.vue
index 38410566c5..7c3df99dfa 100644
--- a/apps/tailwind-components/pages/Form.story.vue
+++ b/apps/tailwind-components/pages/Form.story.vue
@@ -2,6 +2,7 @@
import type { FormFields } from "#build/components";
import type {
columnValue,
+ IColumn,
IFieldError,
ISchemaMetaData,
ITableMetaData,
@@ -41,7 +42,6 @@ const formFields = ref>();
const formValues = ref>({});
function onModelUpdate(value: Record) {
- console.log("story update", value);
formValues.value = value;
}
@@ -50,25 +50,107 @@ const errors = ref>({});
function onErrors(newErrors: Record) {
errors.value = newErrors;
}
+
+function chapterFieldIds(chapterId: string) {
+ const chapterFieldIds = [];
+ let inChapter = false;
+ for (const column of tableMeta.value.columns) {
+ if (column.columnType === "HEADING" && column.id === chapterId) {
+ inChapter = true;
+ } else if (column.columnType === "HEADING" && column.id !== chapterId) {
+ inChapter = false;
+ } else if (inChapter) {
+ chapterFieldIds.push(column.id);
+ }
+ }
+ return chapterFieldIds;
+}
+
+function chapterErrorCount(chapterId: string) {
+ return chapterFieldIds(chapterId).reduce((acc, fieldId) => {
+ return acc + (errors.value[fieldId]?.length ?? 0);
+ }, 0);
+}
+
+const currentSectionDomId = ref("");
+
+const sections = computed(() => {
+ return tableMeta.value?.columns
+ .filter((column: IColumn) => column.columnType == "HEADING")
+ .map((column: IColumn) => {
+ return {
+ label: column.label,
+ domId: column.id,
+ isActive: currentSectionDomId.value.startsWith(column.id),
+ errorCount: chapterErrorCount(column.id),
+ };
+ });
+});
+
+function setUpChapterIsInViewObserver() {
+ if (import.meta.client) {
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ const id = entry.target.getAttribute("id");
+ if (id && entry.intersectionRatio > 0) {
+ currentSectionDomId.value = id;
+ }
+ });
+ },
+ {
+ root: formFields.value?.$el,
+ rootMargin: "0px",
+ threshold: 0.5,
+ }
+ );
+
+ document.querySelectorAll("[id$=chapter-title]").forEach((section) => {
+ observer.observe(section);
+ });
+ }
+}
+
+onMounted(() => setUpChapterIsInViewObserver());
+
+watch(
+ () => tableMeta.value,
+ async () => {
+ await nextTick();
+ setUpChapterIsInViewObserver();
+ }
+);
-
-
-
-
Demo controls, settings and status:
+
+
+
+
Demo controls, settings and status
+