jupiter-dynamic-forms 1.12.2 → 1.14.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.mjs CHANGED
@@ -346,9 +346,9 @@ class FormValidator {
346
346
  static validateField(fieldId, conceptId, columnId, value, fieldType, rules = []) {
347
347
  const errors = [];
348
348
  for (const rule of rules) {
349
- const error = this.validateRule(fieldId, conceptId, columnId, value, fieldType, rule);
350
- if (error) {
351
- errors.push(error);
349
+ const error2 = this.validateRule(fieldId, conceptId, columnId, value, fieldType, rule);
350
+ if (error2) {
351
+ errors.push(error2);
352
352
  }
353
353
  }
354
354
  return errors;
@@ -579,18 +579,25 @@ class XBRLFormBuilder {
579
579
  * @param periodPreferences - User preferences for which period columns to show per role
580
580
  */
581
581
  static buildFormSchema(xbrlInput, periodStartDate, periodEndDate, language = "en", periodPreferences) {
582
- var _a;
582
+ var _a, _b;
583
583
  if (!xbrlInput.presentation || xbrlInput.presentation.length === 0) {
584
584
  throw new Error("XBRL presentation data is required");
585
585
  }
586
586
  const presentationData = xbrlInput.presentation[0];
587
587
  const hypercubeData = (_a = xbrlInput.hypercubes) == null ? void 0 : _a[0];
588
+ const datatypes = Array.isArray(xbrlInput.datatypes) ? xbrlInput.datatypes : ((_b = xbrlInput.datatypes) == null ? void 0 : _b.concepts) || [];
588
589
  const sections = [];
589
590
  const sortedRoles = [...presentationData.roles].sort((a2, b2) => {
590
591
  return a2.role.localeCompare(b2.role);
591
592
  });
592
593
  sortedRoles.forEach((role) => {
593
594
  const section2 = this.buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData, language, periodPreferences);
595
+ if (datatypes && datatypes.length > 0) {
596
+ section2.datatypes = datatypes;
597
+ console.log(`✅ [buildFormSchema] Attached ${datatypes.length} datatypes to section ${section2.id}`);
598
+ } else {
599
+ console.warn(`⚠️ [buildFormSchema] No datatypes available for section ${section2.id}`);
600
+ }
594
601
  this.assignFieldColumnIds(section2);
595
602
  sections.push(section2);
596
603
  });
@@ -660,9 +667,9 @@ class XBRLFormBuilder {
660
667
  columnIds = ["duration"];
661
668
  }
662
669
  columnIds.forEach((columnId) => {
663
- const field = this.createFieldFromConcept(concept, periodStartDate, periodEndDate, columnId);
664
- if (field)
665
- fields.push(field);
670
+ const field2 = this.createFieldFromConcept(concept, periodStartDate, periodEndDate, columnId);
671
+ if (field2)
672
+ fields.push(field2);
666
673
  });
667
674
  }
668
675
  const children = [];
@@ -709,7 +716,7 @@ class XBRLFormBuilder {
709
716
  } else {
710
717
  columnId = "duration";
711
718
  }
712
- const field = {
719
+ const field2 = {
713
720
  id: `${concept.id}_${columnId}_field`,
714
721
  conceptId: concept.id,
715
722
  columnId,
@@ -728,9 +735,9 @@ class XBRLFormBuilder {
728
735
  periodInstantDate: concept.periodType === "instant" ? periodEndDate || periodStartDate || "2025-01-01" : void 0
729
736
  };
730
737
  if (concept.id === "nl-cd_DescriptionLocationNL__a64trl") {
731
- console.log(`🏗️ [Field Creation] Concept: ${concept.id}, periodType from concept: ${concept.periodType}, Field periodType: ${field.periodType}, ColumnId: ${columnId}`);
738
+ console.log(`🏗️ [Field Creation] Concept: ${concept.id}, periodType from concept: ${concept.periodType}, Field periodType: ${field2.periodType}, ColumnId: ${columnId}`);
732
739
  }
733
- return field;
740
+ return field2;
734
741
  }
735
742
  /**
736
743
  * Map XBRL data type to form field type
@@ -786,8 +793,8 @@ class XBRLFormBuilder {
786
793
  * Recursively assign column IDs to fields in a concept tree
787
794
  */
788
795
  static assignColumnIdsToConceptFields(conceptTree, columnIds) {
789
- conceptTree.fields = conceptTree.fields.filter((field) => {
790
- return columnIds.includes(field.columnId);
796
+ conceptTree.fields = conceptTree.fields.filter((field2) => {
797
+ return columnIds.includes(field2.columnId);
791
798
  });
792
799
  if (conceptTree.children) {
793
800
  conceptTree.children.forEach((child) => {
@@ -911,8 +918,8 @@ class XBRLFormBuilder {
911
918
  const date = new Date(dateString);
912
919
  date.setFullYear(date.getFullYear() - 1);
913
920
  return date.toISOString().split("T")[0];
914
- } catch (error) {
915
- console.error(`Error calculating previous year for date ${dateString}:`, error);
921
+ } catch (error2) {
922
+ console.error(`Error calculating previous year for date ${dateString}:`, error2);
916
923
  return dateString;
917
924
  }
918
925
  }
@@ -1500,6 +1507,25 @@ const column$1 = {
1500
1507
  const section$1 = {
1501
1508
  enterPlaceholder: "Enter"
1502
1509
  };
1510
+ const field$1 = {
1511
+ selectOption: "Select an option...",
1512
+ select: "Select...",
1513
+ enterDetailedExplanation: "Enter detailed explanation...",
1514
+ enterAmountNoDecimals: "Enter amount (no decimals)",
1515
+ enterCurrency: "0.00",
1516
+ enterText: "Enter text",
1517
+ enterWholeNumber: "Enter whole number",
1518
+ enterPositiveNumber: "Enter positive number",
1519
+ enterDecimalValue: "Enter decimal value",
1520
+ enterNumberOfShares: "Enter number of shares",
1521
+ yearFormat: "YYYY",
1522
+ enterPercentage: "Enter percentage",
1523
+ emailPlaceholder: "email@example.com",
1524
+ urlPlaceholder: "https://example.com",
1525
+ phonePlaceholder: "+1 (555) 000-0000",
1526
+ enterValue: "Enter value",
1527
+ enterDetailedInformation: "Enter detailed information..."
1528
+ };
1503
1529
  const admin$1 = {
1504
1530
  title: "Configure Roles",
1505
1531
  description: "Select which roles should display the 'Show Previous Year' checkbox and configure period type columns."
@@ -1508,13 +1534,26 @@ const validation$1 = {
1508
1534
  summary: "Please fix the following errors before submitting:",
1509
1535
  errorsFound: "errors found"
1510
1536
  };
1537
+ const error$1 = {
1538
+ popup: {
1539
+ title: "Validation Errors",
1540
+ message: "Please fix the following validation errors before saving:",
1541
+ field: "Field:",
1542
+ value: "Value:",
1543
+ errors: "Errors:",
1544
+ clickToFocus: "Click to focus this field",
1545
+ ok: "OK"
1546
+ }
1547
+ };
1511
1548
  const enTranslations = {
1512
1549
  form: form$1,
1513
1550
  filter: filter$1,
1514
1551
  column: column$1,
1515
1552
  section: section$1,
1553
+ field: field$1,
1516
1554
  admin: admin$1,
1517
- validation: validation$1
1555
+ validation: validation$1,
1556
+ error: error$1
1518
1557
  };
1519
1558
  const form = {
1520
1559
  loading: "Formulier laden...",
@@ -1581,6 +1620,25 @@ const column = {
1581
1620
  const section = {
1582
1621
  enterPlaceholder: "Invoeren"
1583
1622
  };
1623
+ const field = {
1624
+ selectOption: "Selecteer een optie...",
1625
+ select: "Selecteer...",
1626
+ enterDetailedExplanation: "Voer gedetailleerde uitleg in...",
1627
+ enterAmountNoDecimals: "Voer bedrag in (geen decimalen)",
1628
+ enterCurrency: "0,00",
1629
+ enterText: "Voer tekst in",
1630
+ enterWholeNumber: "Voer geheel getal in",
1631
+ enterPositiveNumber: "Voer positief getal in",
1632
+ enterDecimalValue: "Voer decimale waarde in",
1633
+ enterNumberOfShares: "Voer aantal aandelen in",
1634
+ yearFormat: "JJJJ",
1635
+ enterPercentage: "Voer percentage in",
1636
+ emailPlaceholder: "email@voorbeeld.nl",
1637
+ urlPlaceholder: "https://voorbeeld.nl",
1638
+ phonePlaceholder: "+31 (0)20 123 4567",
1639
+ enterValue: "Voer waarde in",
1640
+ enterDetailedInformation: "Voer gedetailleerde informatie in..."
1641
+ };
1584
1642
  const admin = {
1585
1643
  title: "Rollen configureren",
1586
1644
  description: "Selecteer welke rollen het selectievakje 'Vorig jaar weergeven' moeten weergeven en configureer periodetype kolommen."
@@ -1589,13 +1647,26 @@ const validation = {
1589
1647
  summary: "Corrigeer de volgende fouten voordat u indient:",
1590
1648
  errorsFound: "fouten gevonden"
1591
1649
  };
1650
+ const error = {
1651
+ popup: {
1652
+ title: "Validatiefouten",
1653
+ message: "Corrigeer de volgende validatiefouten voordat u opslaat:",
1654
+ field: "Veld:",
1655
+ value: "Waarde:",
1656
+ errors: "Fouten:",
1657
+ clickToFocus: "Klik om dit veld te focussen",
1658
+ ok: "OK"
1659
+ }
1660
+ };
1592
1661
  const nlTranslations = {
1593
1662
  form,
1594
1663
  filter,
1595
1664
  column,
1596
1665
  section,
1666
+ field,
1597
1667
  admin,
1598
- validation
1668
+ validation,
1669
+ error
1599
1670
  };
1600
1671
  const translations = {
1601
1672
  en: enTranslations,
@@ -1707,8 +1778,8 @@ class DraftStorageService {
1707
1778
  customColumns: metadata.customColumns.length
1708
1779
  });
1709
1780
  return true;
1710
- } catch (error) {
1711
- console.error("❌ Failed to save draft:", error);
1781
+ } catch (error2) {
1782
+ console.error("❌ Failed to save draft:", error2);
1712
1783
  return false;
1713
1784
  }
1714
1785
  }
@@ -1736,8 +1807,8 @@ class DraftStorageService {
1736
1807
  metadata,
1737
1808
  version: this.STORAGE_VERSION
1738
1809
  };
1739
- } catch (error) {
1740
- console.error("❌ Failed to load draft:", error);
1810
+ } catch (error2) {
1811
+ console.error("❌ Failed to load draft:", error2);
1741
1812
  return null;
1742
1813
  }
1743
1814
  }
@@ -1756,8 +1827,8 @@ class DraftStorageService {
1756
1827
  if (!metadataStr)
1757
1828
  return null;
1758
1829
  return JSON.parse(metadataStr);
1759
- } catch (error) {
1760
- console.error("❌ Failed to load draft metadata:", error);
1830
+ } catch (error2) {
1831
+ console.error("❌ Failed to load draft metadata:", error2);
1761
1832
  return null;
1762
1833
  }
1763
1834
  }
@@ -1770,8 +1841,8 @@ class DraftStorageService {
1770
1841
  this._storage.removeItem(this.DRAFT_METADATA_KEY);
1771
1842
  console.log("🗑️ Draft cleared successfully");
1772
1843
  return true;
1773
- } catch (error) {
1774
- console.error("❌ Failed to clear draft:", error);
1844
+ } catch (error2) {
1845
+ console.error("❌ Failed to clear draft:", error2);
1775
1846
  return false;
1776
1847
  }
1777
1848
  }
@@ -1831,7 +1902,7 @@ class DraftStorageService {
1831
1902
  /**
1832
1903
  * Create metadata snapshot from current form state
1833
1904
  */
1834
- createMetadataSnapshot(periodStartDate, periodEndDate, language, selectedRoleIds, allSections, typedMemberData, periodPreferences, periodData) {
1905
+ createMetadataSnapshot(periodStartDate, periodEndDate, language, selectedRoleIds, allSections, typedMemberData, periodPreferences, periodData, unitData) {
1835
1906
  return {
1836
1907
  periodStartDate,
1837
1908
  periodEndDate,
@@ -1841,6 +1912,7 @@ class DraftStorageService {
1841
1912
  typedMemberData,
1842
1913
  periodPreferences,
1843
1914
  periodData,
1915
+ unitData,
1844
1916
  schemaVersion: this.STORAGE_VERSION
1845
1917
  };
1846
1918
  }
@@ -1863,6 +1935,204 @@ class DraftStorageService {
1863
1935
  return { compatible, warnings };
1864
1936
  }
1865
1937
  }
1938
+ class XBRLValidator {
1939
+ /**
1940
+ * Validates a value against XBRL datatype validation rules
1941
+ * Only validates when value is not blank
1942
+ *
1943
+ * @param conceptType - The XBRL concept type (e.g., "nl-types:houseNumberNLItemType")
1944
+ * @param value - The input value to validate
1945
+ * @param datatypes - Array of XBRL datatypes from taxonomy
1946
+ * @returns Validation result with errors if any
1947
+ */
1948
+ static validateConceptValue(conceptType, value, datatypes) {
1949
+ const errors = [];
1950
+ if (value === null || value === void 0 || value === "") {
1951
+ return { valid: true, errors: [] };
1952
+ }
1953
+ if (!conceptType || !datatypes || datatypes.length === 0) {
1954
+ return { valid: true, errors: [] };
1955
+ }
1956
+ const datatype = this.findDatatype(conceptType, datatypes);
1957
+ if (!datatype || !datatype.validation) {
1958
+ return { valid: true, errors: [] };
1959
+ }
1960
+ const validation2 = datatype.validation;
1961
+ const stringValue = String(value);
1962
+ if (validation2.pattern) {
1963
+ const patternError = this.validatePattern(stringValue, validation2.pattern);
1964
+ if (patternError) {
1965
+ errors.push(patternError);
1966
+ }
1967
+ }
1968
+ if (validation2.length !== void 0) {
1969
+ const lengthError = this.validateExactLength(stringValue, validation2.length);
1970
+ if (lengthError) {
1971
+ errors.push(lengthError);
1972
+ }
1973
+ }
1974
+ if (validation2.minLength !== void 0) {
1975
+ const minLengthError = this.validateMinLength(stringValue, validation2.minLength);
1976
+ if (minLengthError) {
1977
+ errors.push(minLengthError);
1978
+ }
1979
+ }
1980
+ if (validation2.maxLength !== void 0) {
1981
+ const maxLengthError = this.validateMaxLength(stringValue, validation2.maxLength);
1982
+ if (maxLengthError) {
1983
+ errors.push(maxLengthError);
1984
+ }
1985
+ }
1986
+ if (validation2.totalDigits !== void 0) {
1987
+ const totalDigitsError = this.validateTotalDigits(stringValue, validation2.totalDigits);
1988
+ if (totalDigitsError) {
1989
+ errors.push(totalDigitsError);
1990
+ }
1991
+ }
1992
+ return {
1993
+ valid: errors.length === 0,
1994
+ errors
1995
+ };
1996
+ }
1997
+ /**
1998
+ * Finds the datatype definition for a given concept type
1999
+ * Handles both exact matches and base type chain resolution
2000
+ */
2001
+ static findDatatype(conceptType, datatypes) {
2002
+ let datatype = datatypes.find((dt) => dt.type === conceptType);
2003
+ if (datatype) {
2004
+ return datatype;
2005
+ }
2006
+ const visited = /* @__PURE__ */ new Set();
2007
+ let currentType = conceptType;
2008
+ while (currentType && !visited.has(currentType)) {
2009
+ visited.add(currentType);
2010
+ datatype = datatypes.find((dt) => dt.type === currentType);
2011
+ if (datatype) {
2012
+ if (datatype.validation) {
2013
+ return datatype;
2014
+ }
2015
+ currentType = datatype.basetype;
2016
+ } else {
2017
+ break;
2018
+ }
2019
+ }
2020
+ return void 0;
2021
+ }
2022
+ /**
2023
+ * Validates that value matches the regex pattern
2024
+ */
2025
+ static validatePattern(value, pattern) {
2026
+ try {
2027
+ const regex = new RegExp(`^${pattern}$`);
2028
+ if (!regex.test(value)) {
2029
+ return {
2030
+ type: "pattern",
2031
+ message: `Value does not match required pattern: ${pattern}`,
2032
+ expectedValue: pattern,
2033
+ actualValue: value
2034
+ };
2035
+ }
2036
+ } catch (error2) {
2037
+ console.error(`Invalid regex pattern: ${pattern}`, error2);
2038
+ return {
2039
+ type: "pattern",
2040
+ message: `Invalid pattern configuration: ${pattern}`,
2041
+ expectedValue: pattern,
2042
+ actualValue: value
2043
+ };
2044
+ }
2045
+ return null;
2046
+ }
2047
+ /**
2048
+ * Validates that value has exact length
2049
+ */
2050
+ static validateExactLength(value, requiredLength) {
2051
+ if (value.length !== requiredLength) {
2052
+ return {
2053
+ type: "length",
2054
+ message: `Value must be exactly ${requiredLength} characters (current: ${value.length})`,
2055
+ expectedValue: requiredLength,
2056
+ actualValue: value.length
2057
+ };
2058
+ }
2059
+ return null;
2060
+ }
2061
+ /**
2062
+ * Validates minimum length
2063
+ */
2064
+ static validateMinLength(value, minLength) {
2065
+ if (value.length < minLength) {
2066
+ return {
2067
+ type: "minLength",
2068
+ message: `Value must be at least ${minLength} characters (current: ${value.length})`,
2069
+ expectedValue: minLength,
2070
+ actualValue: value.length
2071
+ };
2072
+ }
2073
+ return null;
2074
+ }
2075
+ /**
2076
+ * Validates maximum length
2077
+ */
2078
+ static validateMaxLength(value, maxLength) {
2079
+ if (value.length > maxLength) {
2080
+ return {
2081
+ type: "maxLength",
2082
+ message: `Value must not exceed ${maxLength} characters (current: ${value.length})`,
2083
+ expectedValue: maxLength,
2084
+ actualValue: value.length
2085
+ };
2086
+ }
2087
+ return null;
2088
+ }
2089
+ /**
2090
+ * Validates total digits (for numeric values)
2091
+ */
2092
+ static validateTotalDigits(value, totalDigits) {
2093
+ const digitsOnly = value.replace(/[^\d]/g, "");
2094
+ if (digitsOnly.length > totalDigits) {
2095
+ return {
2096
+ type: "totalDigits",
2097
+ message: `Value must not exceed ${totalDigits} total digits (current: ${digitsOnly.length})`,
2098
+ expectedValue: totalDigits,
2099
+ actualValue: digitsOnly.length
2100
+ };
2101
+ }
2102
+ return null;
2103
+ }
2104
+ /**
2105
+ * Gets a human-readable summary of validation rules for a concept type
2106
+ * Useful for displaying validation hints to users
2107
+ */
2108
+ static getValidationRulesSummary(conceptType, datatypes) {
2109
+ if (!conceptType || !datatypes) {
2110
+ return [];
2111
+ }
2112
+ const datatype = this.findDatatype(conceptType, datatypes);
2113
+ if (!datatype || !datatype.validation) {
2114
+ return [];
2115
+ }
2116
+ const validation2 = datatype.validation;
2117
+ const rules = [];
2118
+ if (validation2.pattern) {
2119
+ rules.push(`Must match pattern: ${validation2.pattern}`);
2120
+ }
2121
+ if (validation2.length !== void 0) {
2122
+ rules.push(`Must be exactly ${validation2.length} characters`);
2123
+ }
2124
+ if (validation2.minLength !== void 0) {
2125
+ rules.push(`Minimum ${validation2.minLength} characters`);
2126
+ }
2127
+ if (validation2.maxLength !== void 0) {
2128
+ rules.push(`Maximum ${validation2.maxLength} characters`);
2129
+ }
2130
+ if (validation2.totalDigits !== void 0) {
2131
+ rules.push(`Maximum ${validation2.totalDigits} total digits`);
2132
+ }
2133
+ return rules;
2134
+ }
2135
+ }
1866
2136
  const TYPE_INPUT_MAP = {
1867
2137
  // ==========================================
1868
2138
  // Dutch XBRL Types (nl-types namespace)
@@ -1870,7 +2140,7 @@ const TYPE_INPUT_MAP = {
1870
2140
  // Text area for long-form explanations
1871
2141
  "nl-types:formattedExplanationItemType": {
1872
2142
  fieldType: "textarea",
1873
- placeholder: "Enter detailed explanation..."
2143
+ placeholder: I18n.t("field.enterDetailedExplanation")
1874
2144
  },
1875
2145
  // Monetary values without decimals (whole numbers only)
1876
2146
  "nl-types:monetaryNoDecimals20ItemType": {
@@ -1878,7 +2148,7 @@ const TYPE_INPUT_MAP = {
1878
2148
  htmlInputType: "number",
1879
2149
  allowDecimals: false,
1880
2150
  step: 1,
1881
- placeholder: "Enter amount (no decimals)"
2151
+ placeholder: I18n.t("field.enterAmountNoDecimals")
1882
2152
  },
1883
2153
  // ==========================================
1884
2154
  // Standard XBRL Types (xbrli namespace)
@@ -1889,13 +2159,13 @@ const TYPE_INPUT_MAP = {
1889
2159
  htmlInputType: "number",
1890
2160
  allowDecimals: true,
1891
2161
  step: 0.01,
1892
- placeholder: "0.00"
2162
+ placeholder: I18n.t("field.enterCurrency")
1893
2163
  },
1894
2164
  // String/text types
1895
2165
  "xbrli:stringItemType": {
1896
2166
  fieldType: "text",
1897
2167
  htmlInputType: "text",
1898
- placeholder: "Enter text"
2168
+ placeholder: I18n.t("field.enterText")
1899
2169
  },
1900
2170
  // Date types
1901
2171
  "xbrli:dateItemType": {
@@ -1912,7 +2182,7 @@ const TYPE_INPUT_MAP = {
1912
2182
  htmlInputType: "number",
1913
2183
  allowDecimals: false,
1914
2184
  step: 1,
1915
- placeholder: "Enter whole number"
2185
+ placeholder: I18n.t("field.enterWholeNumber")
1916
2186
  },
1917
2187
  "xbrli:nonNegativeIntegerItemType": {
1918
2188
  fieldType: "integer",
@@ -1920,7 +2190,7 @@ const TYPE_INPUT_MAP = {
1920
2190
  allowDecimals: false,
1921
2191
  min: 0,
1922
2192
  step: 1,
1923
- placeholder: "Enter positive number"
2193
+ placeholder: I18n.t("field.enterPositiveNumber")
1924
2194
  },
1925
2195
  "xbrli:positiveIntegerItemType": {
1926
2196
  fieldType: "integer",
@@ -1928,7 +2198,7 @@ const TYPE_INPUT_MAP = {
1928
2198
  allowDecimals: false,
1929
2199
  min: 1,
1930
2200
  step: 1,
1931
- placeholder: "Enter positive number"
2201
+ placeholder: I18n.t("field.enterPositiveNumber")
1932
2202
  },
1933
2203
  // Numeric types - decimals
1934
2204
  "xbrli:decimalItemType": {
@@ -1936,7 +2206,7 @@ const TYPE_INPUT_MAP = {
1936
2206
  htmlInputType: "number",
1937
2207
  allowDecimals: true,
1938
2208
  step: "any",
1939
- placeholder: "Enter decimal value"
2209
+ placeholder: I18n.t("field.enterDecimalValue")
1940
2210
  },
1941
2211
  // Shares (typically whole numbers or with limited decimals)
1942
2212
  "xbrli:sharesItemType": {
@@ -1945,7 +2215,7 @@ const TYPE_INPUT_MAP = {
1945
2215
  allowDecimals: true,
1946
2216
  min: 0,
1947
2217
  step: 0.01,
1948
- placeholder: "Enter number of shares"
2218
+ placeholder: I18n.t("field.enterNumberOfShares")
1949
2219
  },
1950
2220
  "xbrli:shares": {
1951
2221
  fieldType: "number",
@@ -1953,7 +2223,7 @@ const TYPE_INPUT_MAP = {
1953
2223
  allowDecimals: true,
1954
2224
  min: 0,
1955
2225
  step: 0.01,
1956
- placeholder: "Enter number of shares"
2226
+ placeholder: I18n.t("field.enterNumberOfShares")
1957
2227
  },
1958
2228
  // Year (gYear)
1959
2229
  "xbrli:gYearItemType": {
@@ -1963,7 +2233,7 @@ const TYPE_INPUT_MAP = {
1963
2233
  min: 1900,
1964
2234
  max: 2100,
1965
2235
  step: 1,
1966
- placeholder: "YYYY"
2236
+ placeholder: I18n.t("field.yearFormat")
1967
2237
  },
1968
2238
  // Boolean types
1969
2239
  "xbrli:booleanItemType": {
@@ -1977,14 +2247,14 @@ const TYPE_INPUT_MAP = {
1977
2247
  htmlInputType: "number",
1978
2248
  allowDecimals: true,
1979
2249
  step: 0.01,
1980
- placeholder: "Enter percentage"
2250
+ placeholder: I18n.t("field.enterPercentage")
1981
2251
  },
1982
2252
  "xbrli:percentItemType": {
1983
2253
  fieldType: "percentage",
1984
2254
  htmlInputType: "number",
1985
2255
  allowDecimals: true,
1986
2256
  step: 0.01,
1987
- placeholder: "Enter percentage"
2257
+ placeholder: I18n.t("field.enterPercentage")
1988
2258
  },
1989
2259
  // ==========================================
1990
2260
  // Contact/Communication types
@@ -1992,27 +2262,36 @@ const TYPE_INPUT_MAP = {
1992
2262
  "xbrli:emailItemType": {
1993
2263
  fieldType: "email",
1994
2264
  htmlInputType: "email",
1995
- placeholder: "email@example.com"
2265
+ placeholder: I18n.t("field.emailPlaceholder")
1996
2266
  },
1997
2267
  "xbrli:urlItemType": {
1998
2268
  fieldType: "url",
1999
2269
  htmlInputType: "url",
2000
- placeholder: "https://example.com"
2270
+ placeholder: I18n.t("field.urlPlaceholder")
2001
2271
  },
2002
2272
  "xbrli:telephoneItemType": {
2003
2273
  fieldType: "tel",
2004
2274
  htmlInputType: "tel",
2005
- placeholder: "+1 (555) 000-0000"
2275
+ placeholder: I18n.t("field.phonePlaceholder")
2006
2276
  }
2007
2277
  };
2008
- function getInputTypeForConceptType(conceptType) {
2278
+ function getInputTypeForConceptType(conceptType, datatypes) {
2009
2279
  if (!conceptType) {
2010
2280
  return {
2011
2281
  fieldType: "text",
2012
2282
  htmlInputType: "text",
2013
- placeholder: "Enter value"
2283
+ placeholder: I18n.t("field.enterValue")
2014
2284
  };
2015
2285
  }
2286
+ if (datatypes && datatypes.length > 0) {
2287
+ const baseTypeChain = resolveBaseTypeChain(conceptType, datatypes);
2288
+ if (baseTypeChain.length > 0) {
2289
+ const config = determineInputTypeFromBaseChain(baseTypeChain, datatypes);
2290
+ console.log(`🔍 [Type Resolution] ${conceptType} → Chain:`, baseTypeChain, "→ Type:", config.fieldType, config.enumerations ? `(${config.enumerations.length} options)` : "");
2291
+ return config;
2292
+ }
2293
+ }
2294
+ console.log(`⚠️ [Type Resolution Fallback] Using pattern matching for: ${conceptType}`);
2016
2295
  if (TYPE_INPUT_MAP[conceptType]) {
2017
2296
  return TYPE_INPUT_MAP[conceptType];
2018
2297
  }
@@ -2024,7 +2303,7 @@ function getInputTypeForConceptType(conceptType) {
2024
2303
  htmlInputType: "number",
2025
2304
  allowDecimals: false,
2026
2305
  step: 1,
2027
- placeholder: "Enter amount (no decimals)"
2306
+ placeholder: I18n.t("field.enterAmountNoDecimals")
2028
2307
  };
2029
2308
  }
2030
2309
  return {
@@ -2032,13 +2311,13 @@ function getInputTypeForConceptType(conceptType) {
2032
2311
  htmlInputType: "number",
2033
2312
  allowDecimals: true,
2034
2313
  step: 0.01,
2035
- placeholder: "0.00"
2314
+ placeholder: I18n.t("field.enterCurrency")
2036
2315
  };
2037
2316
  }
2038
2317
  if (lowerType.includes("explanation") || lowerType.includes("description") || lowerType.includes("notes") || lowerType.includes("formatted")) {
2039
2318
  return {
2040
2319
  fieldType: "textarea",
2041
- placeholder: "Enter detailed information..."
2320
+ placeholder: I18n.t("field.enterDetailedInformation")
2042
2321
  };
2043
2322
  }
2044
2323
  if (lowerType.includes("date")) {
@@ -2067,7 +2346,7 @@ function getInputTypeForConceptType(conceptType) {
2067
2346
  allowDecimals: false,
2068
2347
  min: isPositive ? 1 : isNonNegative ? 0 : void 0,
2069
2348
  step: 1,
2070
- placeholder: "Enter whole number"
2349
+ placeholder: I18n.t("field.enterWholeNumber")
2071
2350
  };
2072
2351
  }
2073
2352
  if (lowerType.includes("decimal") || lowerType.includes("numeric") || lowerType.includes("number")) {
@@ -2076,7 +2355,7 @@ function getInputTypeForConceptType(conceptType) {
2076
2355
  htmlInputType: "number",
2077
2356
  allowDecimals: true,
2078
2357
  step: "any",
2079
- placeholder: "Enter decimal value"
2358
+ placeholder: I18n.t("field.enterDecimalValue")
2080
2359
  };
2081
2360
  }
2082
2361
  if (lowerType.includes("percent") || lowerType.includes("pure")) {
@@ -2085,13 +2364,13 @@ function getInputTypeForConceptType(conceptType) {
2085
2364
  htmlInputType: "number",
2086
2365
  allowDecimals: true,
2087
2366
  step: 0.01,
2088
- placeholder: "Enter percentage"
2367
+ placeholder: I18n.t("field.enterPercentage")
2089
2368
  };
2090
2369
  }
2091
2370
  return {
2092
2371
  fieldType: "text",
2093
2372
  htmlInputType: "text",
2094
- placeholder: "Enter value"
2373
+ placeholder: I18n.t("field.enterValue")
2095
2374
  };
2096
2375
  }
2097
2376
  function isTextareaType(fieldType) {
@@ -2106,6 +2385,145 @@ function isNumericType(fieldType) {
2106
2385
  function isSelectType(fieldType) {
2107
2386
  return fieldType === "select";
2108
2387
  }
2388
+ function resolveBaseTypeChain(typeName, datatypes) {
2389
+ const baseTypeChain = [];
2390
+ if (!typeName) {
2391
+ return baseTypeChain;
2392
+ }
2393
+ if (!datatypes || datatypes.length === 0) {
2394
+ baseTypeChain.push(typeName);
2395
+ return baseTypeChain;
2396
+ }
2397
+ let currentType = typeName;
2398
+ const visitedTypes = /* @__PURE__ */ new Set();
2399
+ while (currentType) {
2400
+ baseTypeChain.push(currentType);
2401
+ if (visitedTypes.has(currentType)) {
2402
+ console.warn(`Circular reference detected in datatype hierarchy for type: ${currentType}`);
2403
+ break;
2404
+ }
2405
+ visitedTypes.add(currentType);
2406
+ const foundDatatype = datatypes.find((dt) => dt.type === currentType);
2407
+ if (!foundDatatype || !foundDatatype.basetype || foundDatatype.basetype.trim() === "") {
2408
+ break;
2409
+ }
2410
+ currentType = foundDatatype.basetype;
2411
+ }
2412
+ return baseTypeChain;
2413
+ }
2414
+ function collectEnumerationsFromChain(baseTypeChain, datatypes) {
2415
+ if (!baseTypeChain || baseTypeChain.length === 0 || !datatypes || datatypes.length === 0) {
2416
+ return void 0;
2417
+ }
2418
+ for (const typeName of baseTypeChain) {
2419
+ const datatype = datatypes.find((dt) => dt.type === typeName);
2420
+ if (datatype && datatype.enumerations && datatype.enumerations.length > 0) {
2421
+ return datatype.enumerations.map((enumItem) => ({
2422
+ id: enumItem.id || enumItem.value,
2423
+ // Use value as fallback if id not present
2424
+ value: enumItem.value,
2425
+ label: enumItem.value
2426
+ // Use value as display label
2427
+ }));
2428
+ }
2429
+ }
2430
+ return void 0;
2431
+ }
2432
+ function determineInputTypeFromBaseChain(baseTypeChain, datatypes) {
2433
+ if (!baseTypeChain || baseTypeChain.length === 0) {
2434
+ return {
2435
+ fieldType: "text",
2436
+ htmlInputType: "text",
2437
+ placeholder: I18n.t("field.enterValue")
2438
+ };
2439
+ }
2440
+ if (datatypes && datatypes.length > 0) {
2441
+ const enumerations = collectEnumerationsFromChain(baseTypeChain, datatypes);
2442
+ if (enumerations && enumerations.length > 0) {
2443
+ return {
2444
+ fieldType: "select",
2445
+ enumerations,
2446
+ placeholder: I18n.t("field.selectOption")
2447
+ };
2448
+ }
2449
+ }
2450
+ const chainLower = baseTypeChain.map((type) => type.toLowerCase());
2451
+ const chainString = chainLower.join("|");
2452
+ if (baseTypeChain.some((type) => type === "nl-types:formattedExplanationItemType") || chainString.includes("formattedexplanation") || chainString.includes("formatted") && chainString.includes("explanation")) {
2453
+ return {
2454
+ fieldType: "textarea",
2455
+ placeholder: I18n.t("field.enterDetailedExplanation")
2456
+ };
2457
+ }
2458
+ if (chainLower.some((type) => type.includes("date"))) {
2459
+ if (chainString.includes("datetime") || chainString.includes("time")) {
2460
+ return {
2461
+ fieldType: "datetime",
2462
+ htmlInputType: "datetime-local"
2463
+ };
2464
+ }
2465
+ return {
2466
+ fieldType: "date",
2467
+ htmlInputType: "date"
2468
+ };
2469
+ }
2470
+ if (chainLower.some((type) => type.includes("boolean") || type.includes("bool"))) {
2471
+ return {
2472
+ fieldType: "boolean"
2473
+ };
2474
+ }
2475
+ if (chainLower.some((type) => type.includes("integer") || type === "integer")) {
2476
+ const isNonNegative = chainString.includes("nonnegative") || chainString.includes("non-negative");
2477
+ const isPositive = chainString.includes("positive");
2478
+ return {
2479
+ fieldType: "integer",
2480
+ htmlInputType: "number",
2481
+ allowDecimals: false,
2482
+ min: isPositive ? 1 : isNonNegative ? 0 : void 0,
2483
+ step: 1,
2484
+ placeholder: I18n.t("field.enterWholeNumber")
2485
+ };
2486
+ }
2487
+ if (chainLower.some((type) => type.includes("decimal") || type === "decimal")) {
2488
+ if (chainString.includes("monetary") || chainString.includes("currency")) {
2489
+ if (chainString.includes("nodecimals") || chainString.includes("no-decimals") || chainString.includes("nodecimals20")) {
2490
+ return {
2491
+ fieldType: "number",
2492
+ htmlInputType: "number",
2493
+ allowDecimals: false,
2494
+ step: 1,
2495
+ placeholder: I18n.t("field.enterAmountNoDecimals")
2496
+ };
2497
+ }
2498
+ return {
2499
+ fieldType: "currency",
2500
+ htmlInputType: "number",
2501
+ allowDecimals: true,
2502
+ step: 0.01,
2503
+ placeholder: I18n.t("field.enterCurrency")
2504
+ };
2505
+ }
2506
+ return {
2507
+ fieldType: "decimal",
2508
+ htmlInputType: "number",
2509
+ allowDecimals: true,
2510
+ step: "any",
2511
+ placeholder: I18n.t("field.enterDecimalValue")
2512
+ };
2513
+ }
2514
+ if (baseTypeChain.some((type) => type === "xbrli:stringItemType") || chainLower.some((type) => type === "string" || type.includes("stringitem"))) {
2515
+ return {
2516
+ fieldType: "text",
2517
+ htmlInputType: "text",
2518
+ placeholder: I18n.t("field.enterText")
2519
+ };
2520
+ }
2521
+ return {
2522
+ fieldType: "text",
2523
+ htmlInputType: "text",
2524
+ placeholder: I18n.t("field.enterValue")
2525
+ };
2526
+ }
2109
2527
  var __defProp$5 = Object.defineProperty;
2110
2528
  var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
2111
2529
  var __decorateClass$5 = (decorators, target, key, kind) => {
@@ -2120,18 +2538,35 @@ var __decorateClass$5 = (decorators, target, key, kind) => {
2120
2538
  let JupiterFormField = class extends LitElement {
2121
2539
  constructor() {
2122
2540
  super(...arguments);
2541
+ this.defaultUnits = [];
2123
2542
  this.value = null;
2124
2543
  this.disabled = false;
2125
2544
  this.locale = "en-US";
2126
2545
  this.hideLabel = false;
2127
2546
  this._errors = [];
2547
+ this._xbrlErrors = [];
2128
2548
  this._touched = false;
2129
2549
  this._showPeriodPopup = false;
2550
+ this._availableUnits = [];
2130
2551
  }
2131
2552
  willUpdate(changedProperties) {
2553
+ var _a;
2132
2554
  if (changedProperties.has("value") || changedProperties.has("field")) {
2133
2555
  this._validateField();
2134
2556
  }
2557
+ if (changedProperties.has("unit") && this.unit) {
2558
+ console.log(`🏷️ [FormField willUpdate] Unit property changed to: ${this.unit}, conceptId: ${this.conceptId}, columnId: ${this.columnId}`);
2559
+ this.dispatchEvent(new CustomEvent("unit-change", {
2560
+ detail: {
2561
+ fieldId: (_a = this.field) == null ? void 0 : _a.id,
2562
+ conceptId: this.conceptId,
2563
+ columnId: this.columnId,
2564
+ unit: this.unit
2565
+ },
2566
+ bubbles: true,
2567
+ composed: true
2568
+ }));
2569
+ }
2135
2570
  if (changedProperties.has("field") && this.field) {
2136
2571
  if (this.conceptId.includes("DescriptionLocationNL") || this.columnId.startsWith("col-")) {
2137
2572
  console.log(`📅 [FormField willUpdate] Concept ${this.conceptId}, Column ${this.columnId}: field.periodType=${this.field.periodType}, field.periodStartDate=${this.field.periodStartDate}, field.periodEndDate=${this.field.periodEndDate}, field.periodInstantDate=${this.field.periodInstantDate}`);
@@ -2184,21 +2619,138 @@ let JupiterFormField = class extends LitElement {
2184
2619
  }
2185
2620
  _handleBlur() {
2186
2621
  this._touched = true;
2622
+ this._validateXBRLDatatype();
2623
+ console.log(`🟦 [FormField] Blur event - fieldId: ${this.field.id}, conceptId: ${this.conceptId}, columnId: ${this.columnId}`);
2624
+ console.log(`🟦 [FormField] Current _xbrlErrors:`, this._xbrlErrors);
2625
+ console.log(`🟦 [FormField] Current value:`, this.value);
2187
2626
  this.dispatchEvent(new CustomEvent("field-blur", {
2188
2627
  detail: {
2189
2628
  fieldId: this.field.id,
2190
2629
  conceptId: this.conceptId,
2191
- columnId: this.columnId
2630
+ columnId: this.columnId,
2631
+ xbrlValidationErrors: this._xbrlErrors
2192
2632
  },
2193
- bubbles: true
2633
+ bubbles: true,
2634
+ composed: true
2635
+ // CRITICAL: Allow event to cross Shadow DOM boundaries
2194
2636
  }));
2637
+ console.log(`🟦 [FormField] Dispatched field-blur event with ${this._xbrlErrors.length} errors`);
2638
+ }
2639
+ /**
2640
+ * Validates the current value against XBRL datatype validation rules
2641
+ * Called on blur event when user loses focus on the input field
2642
+ */
2643
+ _validateXBRLDatatype() {
2644
+ this._xbrlErrors = [];
2645
+ if (this.value === null || this.value === void 0 || this.value === "") {
2646
+ return;
2647
+ }
2648
+ if (!this.conceptType || !this.datatypes || this.datatypes.length === 0) {
2649
+ return;
2650
+ }
2651
+ const validationResult = XBRLValidator.validateConceptValue(
2652
+ this.conceptType,
2653
+ this.value,
2654
+ this.datatypes
2655
+ );
2656
+ if (!validationResult.valid) {
2657
+ this._xbrlErrors = validationResult.errors;
2658
+ console.log(`❌ [FormField] XBRL Validation failed for ${this.conceptId}:`, {
2659
+ conceptType: this.conceptType,
2660
+ value: this.value,
2661
+ errors: this._xbrlErrors
2662
+ });
2663
+ } else {
2664
+ console.log(`✅ [FormField] XBRL Validation passed for ${this.conceptId}`);
2665
+ }
2195
2666
  }
2196
2667
  _handlePeriodIconClick() {
2668
+ this._availableUnits = this._collectUnitsForConceptType();
2669
+ console.log(`📊 [FormField] Collected ${this._availableUnits.length} units for concept ${this.conceptId}:`, this._availableUnits);
2670
+ console.log(`📊 [FormField] Current unit value: ${this.unit}`);
2671
+ console.log(`📊 [FormField] ConceptId: ${this.conceptId}, ColumnId: ${this.columnId}`);
2672
+ if (!this.unit && this._availableUnits.length > 0) {
2673
+ let unitToSelect = null;
2674
+ const defaultUnit = this._availableUnits.find((u2) => u2.isDefault === true);
2675
+ if (defaultUnit) {
2676
+ unitToSelect = defaultUnit.id;
2677
+ console.log(`🎯 [FormField] Auto-selecting default unit: ${defaultUnit.id} (${defaultUnit.label})`);
2678
+ } else if (this._availableUnits.length === 1) {
2679
+ unitToSelect = this._availableUnits[0].id;
2680
+ console.log(`🎯 [FormField] Auto-selecting single available unit: ${unitToSelect}`);
2681
+ }
2682
+ if (unitToSelect) {
2683
+ this.unit = unitToSelect;
2684
+ this.dispatchEvent(new CustomEvent("unit-change", {
2685
+ detail: {
2686
+ fieldId: this.field.id,
2687
+ conceptId: this.conceptId,
2688
+ columnId: this.columnId,
2689
+ unit: this.unit
2690
+ },
2691
+ bubbles: true,
2692
+ composed: true
2693
+ }));
2694
+ }
2695
+ } else if (this.unit) {
2696
+ console.log(`📊 [FormField] Unit already set, dispatching unit-change to ensure parent stores it: ${this.unit}`);
2697
+ this.dispatchEvent(new CustomEvent("unit-change", {
2698
+ detail: {
2699
+ fieldId: this.field.id,
2700
+ conceptId: this.conceptId,
2701
+ columnId: this.columnId,
2702
+ unit: this.unit
2703
+ },
2704
+ bubbles: true,
2705
+ composed: true
2706
+ }));
2707
+ }
2197
2708
  this._showPeriodPopup = true;
2198
2709
  }
2710
+ /**
2711
+ * Collects units from the concept's type or its basetype chain
2712
+ * @returns Array of unit objects with id, label, and isDefault
2713
+ */
2714
+ _collectUnitsForConceptType() {
2715
+ if (!this.conceptType || !this.datatypes) {
2716
+ return [];
2717
+ }
2718
+ const baseTypeChain = resolveBaseTypeChain(this.conceptType, this.datatypes);
2719
+ console.log(`🔍 [Unit Resolution] Concept: ${this.conceptId}, Type: ${this.conceptType}, BaseType Chain:`, baseTypeChain);
2720
+ for (const typeName of baseTypeChain) {
2721
+ const datatype = this.datatypes.find((dt) => dt.type === typeName);
2722
+ if (datatype && datatype.units && Array.isArray(datatype.units) && datatype.units.length > 0) {
2723
+ console.log(`✅ [Unit Resolution] Found ${datatype.units.length} units in type: ${typeName}`);
2724
+ return datatype.units;
2725
+ }
2726
+ }
2727
+ console.log(`ℹ️ [Unit Resolution] No units found for concept ${this.conceptId}`);
2728
+ return [];
2729
+ }
2199
2730
  _closePeriodPopup() {
2200
2731
  this._showPeriodPopup = false;
2201
2732
  }
2733
+ _handleUnitChange(event) {
2734
+ const target = event.target;
2735
+ const value = target.value;
2736
+ console.log(`🏷️ [FormField] Unit change detected: value=${value}, conceptId=${this.conceptId}, columnId=${this.columnId}`);
2737
+ console.log(`🏷️ [FormField] Previous unit value: ${this.unit}`);
2738
+ this.unit = value;
2739
+ console.log(`🏷️ [FormField] Updated unit value to: ${this.unit}`);
2740
+ const eventDetail = {
2741
+ fieldId: this.field.id,
2742
+ conceptId: this.conceptId,
2743
+ columnId: this.columnId,
2744
+ unit: this.unit
2745
+ };
2746
+ console.log(`🏷️ [FormField] Dispatching unit-change event with detail:`, eventDetail);
2747
+ this.dispatchEvent(new CustomEvent("unit-change", {
2748
+ detail: eventDetail,
2749
+ bubbles: true,
2750
+ composed: true
2751
+ }));
2752
+ console.log(`🏷️ [FormField] unit-change event dispatched`);
2753
+ }
2202
2754
  _handlePopupOverlayClick(e2) {
2203
2755
  if (e2.target === e2.currentTarget) {
2204
2756
  this._closePeriodPopup();
@@ -2224,7 +2776,8 @@ let JupiterFormField = class extends LitElement {
2224
2776
  periodType: this.field.periodType,
2225
2777
  periodStartDate: this.periodStartDate,
2226
2778
  periodEndDate: this.periodEndDate,
2227
- periodInstantDate: this.periodInstantDate
2779
+ periodInstantDate: this.periodInstantDate,
2780
+ unit: this.unit
2228
2781
  },
2229
2782
  bubbles: true,
2230
2783
  composed: true
@@ -2237,13 +2790,12 @@ let JupiterFormField = class extends LitElement {
2237
2790
  });
2238
2791
  }
2239
2792
  _renderInput() {
2240
- var _a;
2241
2793
  const hasErrors = this._errors.some((e2) => e2.severity === "error");
2242
2794
  const hasWarnings = this._errors.some((e2) => e2.severity === "warning");
2243
2795
  const cssClass = `field-input ${hasErrors ? "error" : hasWarnings ? "warning" : ""}`;
2244
2796
  const fieldId = `${this.conceptId}__${this.columnId}`;
2245
2797
  const fieldName = `data[${this.conceptId}][${this.columnId}]`;
2246
- const typeConfig = getInputTypeForConceptType(this.conceptType);
2798
+ const typeConfig = getInputTypeForConceptType(this.conceptType, this.datatypes);
2247
2799
  if (this.conceptType)
2248
2800
  ;
2249
2801
  const effectiveFieldType = typeConfig.fieldType || this.field.type || "text";
@@ -2263,6 +2815,7 @@ let JupiterFormField = class extends LitElement {
2263
2815
  `;
2264
2816
  }
2265
2817
  if (effectiveFieldType === "select" || this.field.type === "select") {
2818
+ const selectOptions = typeConfig.enumerations || this.field.options || [];
2266
2819
  return html`
2267
2820
  <select
2268
2821
  id="${fieldId}"
@@ -2274,16 +2827,21 @@ let JupiterFormField = class extends LitElement {
2274
2827
  @focus="${this._handleFocus}"
2275
2828
  @blur="${this._handleBlur}"
2276
2829
  >
2277
- <option value="">Select...</option>
2278
- ${(_a = this.field.options) == null ? void 0 : _a.map((option) => html`
2279
- <option
2280
- value="${option.value}"
2281
- ?disabled="${option.disabled}"
2282
- ?selected="${this.value === option.value}"
2283
- >
2284
- ${option.label}
2285
- </option>
2286
- `)}
2830
+ <option value="">${typeConfig.placeholder || I18n.t("field.select")}</option>
2831
+ ${selectOptions.map((option) => {
2832
+ const optionValue = option.value;
2833
+ const optionLabel = option.label || option.value;
2834
+ const isDisabled = option.disabled || false;
2835
+ return html`
2836
+ <option
2837
+ value="${optionValue}"
2838
+ ?disabled="${isDisabled}"
2839
+ ?selected="${this.value === optionValue}"
2840
+ >
2841
+ ${optionLabel}
2842
+ </option>
2843
+ `;
2844
+ })}
2287
2845
  </select>
2288
2846
  `;
2289
2847
  }
@@ -2431,6 +2989,25 @@ let JupiterFormField = class extends LitElement {
2431
2989
  />
2432
2990
  </div>
2433
2991
  `}
2992
+
2993
+ ${this._availableUnits.length > 0 ? html`
2994
+ <div class="period-controls">
2995
+ <label>Unit:</label>
2996
+ <select
2997
+ .value="${this.unit || ""}"
2998
+ @change="${this._handleUnitChange}"
2999
+ ?disabled="${this.disabled}"
3000
+ class="unit-select"
3001
+ >
3002
+ <option value="">Select Unit</option>
3003
+ ${this._availableUnits.map((unit) => html`
3004
+ <option value="${unit.id}" ?selected="${this.unit === unit.id}">
3005
+ ${unit.label || unit.id}
3006
+ </option>
3007
+ `)}
3008
+ </select>
3009
+ </div>
3010
+ ` : ""}
2434
3011
  </div>
2435
3012
  </div>
2436
3013
  </div>
@@ -2464,9 +3041,19 @@ let JupiterFormField = class extends LitElement {
2464
3041
 
2465
3042
  ${this._errors.length > 0 && this._touched ? html`
2466
3043
  <div class="field-errors">
2467
- ${this._errors.map((error) => html`
2468
- <span class="field-error ${error.severity}">
2469
- ${error.message}
3044
+ ${this._errors.map((error2) => html`
3045
+ <span class="field-error ${error2.severity}">
3046
+ ${error2.message}
3047
+ </span>
3048
+ `)}
3049
+ </div>
3050
+ ` : ""}
3051
+
3052
+ ${this._xbrlErrors.length > 0 && this._touched ? html`
3053
+ <div class="field-errors">
3054
+ ${this._xbrlErrors.map((error2) => html`
3055
+ <span class="field-error error">
3056
+ ${error2.message}
2470
3057
  </span>
2471
3058
  `)}
2472
3059
  </div>
@@ -2617,6 +3204,28 @@ JupiterFormField.styles = css`
2617
3204
  box-shadow: 0 0 0 2px var(--jupiter-primary-color-light, rgba(25, 118, 210, 0.2));
2618
3205
  }
2619
3206
 
3207
+ .period-popup-content .period-controls .unit-select {
3208
+ padding: 8px 10px;
3209
+ font-size: 14px;
3210
+ border: 1px solid var(--jupiter-border-color, #ddd);
3211
+ border-radius: 4px;
3212
+ background: var(--jupiter-input-background, #fff);
3213
+ color: var(--jupiter-text-primary, #333);
3214
+ cursor: pointer;
3215
+ }
3216
+
3217
+ .period-popup-content .period-controls .unit-select:focus {
3218
+ outline: none;
3219
+ border-color: var(--jupiter-primary-color, #1976d2);
3220
+ box-shadow: 0 0 0 2px var(--jupiter-primary-color-light, rgba(25, 118, 210, 0.2));
3221
+ }
3222
+
3223
+ .period-popup-content .period-controls .unit-select:disabled {
3224
+ background: var(--jupiter-disabled-background, #f5f5f5);
3225
+ color: var(--jupiter-disabled-text, #999);
3226
+ cursor: not-allowed;
3227
+ }
3228
+
2620
3229
  .field-input {
2621
3230
  width: 100%;
2622
3231
  padding: 6px 8px; /* Reduced padding for table cells */
@@ -2733,6 +3342,12 @@ __decorateClass$5([
2733
3342
  __decorateClass$5([
2734
3343
  n2({ type: String })
2735
3344
  ], JupiterFormField.prototype, "conceptType", 2);
3345
+ __decorateClass$5([
3346
+ n2({ type: Array })
3347
+ ], JupiterFormField.prototype, "datatypes", 2);
3348
+ __decorateClass$5([
3349
+ n2({ type: Array })
3350
+ ], JupiterFormField.prototype, "defaultUnits", 2);
2736
3351
  __decorateClass$5([
2737
3352
  n2({ type: String })
2738
3353
  ], JupiterFormField.prototype, "columnId", 2);
@@ -2757,15 +3372,24 @@ __decorateClass$5([
2757
3372
  __decorateClass$5([
2758
3373
  n2({ type: String })
2759
3374
  ], JupiterFormField.prototype, "periodInstantDate", 2);
3375
+ __decorateClass$5([
3376
+ n2({ type: String })
3377
+ ], JupiterFormField.prototype, "unit", 2);
2760
3378
  __decorateClass$5([
2761
3379
  r()
2762
3380
  ], JupiterFormField.prototype, "_errors", 2);
3381
+ __decorateClass$5([
3382
+ r()
3383
+ ], JupiterFormField.prototype, "_xbrlErrors", 2);
2763
3384
  __decorateClass$5([
2764
3385
  r()
2765
3386
  ], JupiterFormField.prototype, "_touched", 2);
2766
3387
  __decorateClass$5([
2767
3388
  r()
2768
3389
  ], JupiterFormField.prototype, "_showPeriodPopup", 2);
3390
+ __decorateClass$5([
3391
+ r()
3392
+ ], JupiterFormField.prototype, "_availableUnits", 2);
2769
3393
  JupiterFormField = __decorateClass$5([
2770
3394
  t$1("jupiter-form-field")
2771
3395
  ], JupiterFormField);
@@ -2785,6 +3409,9 @@ let JupiterConceptTree = class extends LitElement {
2785
3409
  super(...arguments);
2786
3410
  this.columns = [];
2787
3411
  this.formData = {};
3412
+ this.periodData = {};
3413
+ this.unitData = {};
3414
+ this.defaultUnits = [];
2788
3415
  this.disabled = false;
2789
3416
  this.locale = "en-US";
2790
3417
  this.expandedConcepts = /* @__PURE__ */ new Set();
@@ -2812,11 +3439,11 @@ let JupiterConceptTree = class extends LitElement {
2812
3439
  }
2813
3440
  _getFieldForColumn(columnId) {
2814
3441
  var _a;
2815
- return (_a = this.concept.fields) == null ? void 0 : _a.find((field) => field.columnId === columnId);
3442
+ return (_a = this.concept.fields) == null ? void 0 : _a.find((field2) => field2.columnId === columnId);
2816
3443
  }
2817
- _getFieldValue(field) {
3444
+ _getFieldValue(field2) {
2818
3445
  var _a;
2819
- return (_a = this.formData[this.concept.id]) == null ? void 0 : _a[field.columnId];
3446
+ return (_a = this.formData[this.concept.id]) == null ? void 0 : _a[field2.columnId];
2820
3447
  }
2821
3448
  _handleFieldChange(event) {
2822
3449
  event.stopPropagation();
@@ -2859,20 +3486,25 @@ let JupiterConceptTree = class extends LitElement {
2859
3486
 
2860
3487
  <!-- Input Field Cells (Period Columns) - Only for non-abstract concepts -->
2861
3488
  ${this.columns.map((column2) => {
2862
- const field = this._getFieldForColumn(column2.id);
2863
- const shouldShowField = !isAbstract && field;
3489
+ var _a, _b;
3490
+ const field2 = this._getFieldForColumn(column2.id);
3491
+ const shouldShowField = !isAbstract && field2;
3492
+ const storedUnit = (_b = (_a = this.unitData) == null ? void 0 : _a[this.concept.id]) == null ? void 0 : _b[column2.id];
2864
3493
  return html`
2865
3494
  <td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""}">
2866
3495
  ${shouldShowField ? html`
2867
3496
  <jupiter-form-field
2868
- .field="${field}"
3497
+ .field="${field2}"
2869
3498
  .conceptId="${this.concept.id}"
2870
3499
  .conceptType="${this.concept.type}"
3500
+ .datatypes="${this.datatypes}"
3501
+ .defaultUnits="${this.defaultUnits}"
2871
3502
  .columnId="${column2.id}"
2872
- .value="${this._getFieldValue(field)}"
2873
- .periodStartDate="${field.periodStartDate || column2.periodStartDate}"
2874
- .periodEndDate="${field.periodEndDate || column2.periodEndDate}"
2875
- .periodInstantDate="${field.periodInstantDate || (field.periodType === "instant" ? field.periodEndDate || field.periodStartDate : void 0)}"
3503
+ .value="${this._getFieldValue(field2)}"
3504
+ .unit="${storedUnit || ""}"
3505
+ .periodStartDate="${field2.periodStartDate || column2.periodStartDate}"
3506
+ .periodEndDate="${field2.periodEndDate || column2.periodEndDate}"
3507
+ .periodInstantDate="${field2.periodInstantDate || (field2.periodType === "instant" ? field2.periodEndDate || field2.periodStartDate : void 0)}"
2876
3508
  .disabled="${this.disabled}"
2877
3509
  .locale="${this.locale}"
2878
3510
  .hideLabel="${true}"
@@ -2998,6 +3630,15 @@ __decorateClass$4([
2998
3630
  __decorateClass$4([
2999
3631
  n2({ type: Object })
3000
3632
  ], JupiterConceptTree.prototype, "formData", 2);
3633
+ __decorateClass$4([
3634
+ n2({ type: Object })
3635
+ ], JupiterConceptTree.prototype, "periodData", 2);
3636
+ __decorateClass$4([
3637
+ n2({ type: Object })
3638
+ ], JupiterConceptTree.prototype, "unitData", 2);
3639
+ __decorateClass$4([
3640
+ n2({ type: Array })
3641
+ ], JupiterConceptTree.prototype, "defaultUnits", 2);
3001
3642
  __decorateClass$4([
3002
3643
  n2({ type: Boolean })
3003
3644
  ], JupiterConceptTree.prototype, "disabled", 2);
@@ -3007,6 +3648,9 @@ __decorateClass$4([
3007
3648
  __decorateClass$4([
3008
3649
  n2({ type: Set })
3009
3650
  ], JupiterConceptTree.prototype, "expandedConcepts", 2);
3651
+ __decorateClass$4([
3652
+ n2({ type: Array })
3653
+ ], JupiterConceptTree.prototype, "datatypes", 2);
3010
3654
  __decorateClass$4([
3011
3655
  r()
3012
3656
  ], JupiterConceptTree.prototype, "_expanded", 2);
@@ -3061,9 +3705,9 @@ let JupiterAddColumnDialog = class extends LitElement {
3061
3705
  if (!this._isFormValid())
3062
3706
  return;
3063
3707
  const request = {
3064
- periodType: this.periodType === "mixed" ? this._selectedType : this.periodType
3708
+ periodType: this.periodType === "mixed" ? "duration" : this.periodType
3065
3709
  };
3066
- if (this.periodType === "instant" || this.periodType === "mixed" && this._selectedType === "instant") {
3710
+ if (this.periodType === "instant") {
3067
3711
  request.instantDate = this._instantDate;
3068
3712
  } else {
3069
3713
  request.startDate = this._startDate;
@@ -3078,13 +3722,7 @@ let JupiterAddColumnDialog = class extends LitElement {
3078
3722
  }));
3079
3723
  }
3080
3724
  _isFormValid() {
3081
- if (this.periodType === "mixed") {
3082
- if (this._selectedType === "instant") {
3083
- return !!this._instantDate;
3084
- } else {
3085
- return !!this._startDate && !!this._endDate && this._startDate <= this._endDate;
3086
- }
3087
- } else if (this.periodType === "duration") {
3725
+ if (this.periodType === "mixed" || this.periodType === "duration") {
3088
3726
  return !!this._startDate && !!this._endDate && this._startDate <= this._endDate;
3089
3727
  } else if (this.periodType === "instant") {
3090
3728
  return !!this._instantDate;
@@ -3182,22 +3820,7 @@ let JupiterAddColumnDialog = class extends LitElement {
3182
3820
  </div>
3183
3821
 
3184
3822
  <div class="dialog-content">
3185
- ${this.periodType === "mixed" ? html`
3186
- <div class="form-group">
3187
- <label class="form-label required">${I18n.t("column.columnType")}</label>
3188
- <select
3189
- class="form-input"
3190
- .value="${this._selectedType}"
3191
- @change="${this._handleSelectedTypeChange}"
3192
- required
3193
- >
3194
- <option value="instant">${I18n.t("column.instantSingleDate")}</option>
3195
- <option value="duration">${I18n.t("column.durationDates")}</option>
3196
- </select>
3197
- </div>
3198
- ` : ""}
3199
-
3200
- ${this.periodType === "instant" || this.periodType === "mixed" && this._selectedType === "instant" ? html`
3823
+ ${this.periodType === "instant" ? html`
3201
3824
  <div class="form-group">
3202
3825
  <label class="form-label required">${I18n.t("column.instantDate")}</label>
3203
3826
  <input
@@ -3624,7 +4247,10 @@ let JupiterFormSection = class extends LitElement {
3624
4247
  super(...arguments);
3625
4248
  this.columns = [];
3626
4249
  this.formData = {};
4250
+ this.periodData = {};
4251
+ this.unitData = {};
3627
4252
  this.typedMemberData = {};
4253
+ this.defaultUnits = [];
3628
4254
  this.disabled = false;
3629
4255
  this.collapsible = true;
3630
4256
  this.locale = "en-US";
@@ -3984,7 +4610,11 @@ let JupiterFormSection = class extends LitElement {
3984
4610
  <jupiter-concept-tree
3985
4611
  .concept="${concept}"
3986
4612
  .columns="${this.columns}"
4613
+ .datatypes="${this.datatypes}"
3987
4614
  .formData="${this.formData}"
4615
+ .periodData="${this.periodData}"
4616
+ .unitData="${this.unitData}"
4617
+ .defaultUnits="${this.defaultUnits}"
3988
4618
  .disabled="${this.disabled}"
3989
4619
  .locale="${this.locale}"
3990
4620
  .expandedConcepts="${this._expandedConcepts}"
@@ -4275,12 +4905,24 @@ __decorateClass$2([
4275
4905
  __decorateClass$2([
4276
4906
  n2({ type: Array })
4277
4907
  ], JupiterFormSection.prototype, "columns", 2);
4908
+ __decorateClass$2([
4909
+ n2({ type: Array })
4910
+ ], JupiterFormSection.prototype, "datatypes", 2);
4278
4911
  __decorateClass$2([
4279
4912
  n2({ type: Object })
4280
4913
  ], JupiterFormSection.prototype, "formData", 2);
4914
+ __decorateClass$2([
4915
+ n2({ type: Object })
4916
+ ], JupiterFormSection.prototype, "periodData", 2);
4917
+ __decorateClass$2([
4918
+ n2({ type: Object })
4919
+ ], JupiterFormSection.prototype, "unitData", 2);
4281
4920
  __decorateClass$2([
4282
4921
  n2({ type: Object })
4283
4922
  ], JupiterFormSection.prototype, "typedMemberData", 2);
4923
+ __decorateClass$2([
4924
+ n2({ type: Array })
4925
+ ], JupiterFormSection.prototype, "defaultUnits", 2);
4284
4926
  __decorateClass$2([
4285
4927
  n2({ type: Boolean })
4286
4928
  ], JupiterFormSection.prototype, "disabled", 2);
@@ -5069,11 +5711,14 @@ let JupiterDynamicForm = class extends LitElement {
5069
5711
  this.display = "accordion";
5070
5712
  this.mode = "inputForm";
5071
5713
  this.financialStatementsTypeAxis = [];
5714
+ this.defaultUnits = [];
5072
5715
  this._formData = {};
5073
5716
  this._draftLoaded = false;
5074
5717
  this._preservedFormData = {};
5075
5718
  this._periodData = {};
5076
5719
  this._preservedPeriodData = {};
5720
+ this._unitData = {};
5721
+ this._preservedUnitData = {};
5077
5722
  this._typedMemberData = {};
5078
5723
  this._preservedTypedMemberData = {};
5079
5724
  this._columns = [];
@@ -5082,6 +5727,8 @@ let JupiterDynamicForm = class extends LitElement {
5082
5727
  this._dirty = false;
5083
5728
  this._valid = true;
5084
5729
  this._submitted = false;
5730
+ this._xbrlFormErrors = [];
5731
+ this._showErrorPopup = false;
5085
5732
  this._allSections = [];
5086
5733
  this._selectedRoleIds = [];
5087
5734
  this._showFilterDialog = false;
@@ -5100,6 +5747,17 @@ let JupiterDynamicForm = class extends LitElement {
5100
5747
  console.log(`🌍 [GLOBAL DynamicForm] Event detail:`, customEvent.detail);
5101
5748
  this._handlePeriodChange(customEvent);
5102
5749
  });
5750
+ this.addEventListener("unit-change", (e2) => {
5751
+ console.log(`🏷️ [GLOBAL DynamicForm] Caught unit-change event on element:`, e2);
5752
+ const customEvent = e2;
5753
+ console.log(`🏷️ [GLOBAL DynamicForm] Event detail:`, customEvent.detail);
5754
+ this._handleUnitChange(customEvent);
5755
+ });
5756
+ this.addEventListener("field-blur", (e2) => {
5757
+ console.log("🚨 [DynamicForm] field-blur event listener triggered!", e2);
5758
+ const customEvent = e2;
5759
+ this._handleFieldBlur(customEvent);
5760
+ });
5103
5761
  this._initializeForm();
5104
5762
  }
5105
5763
  updated(changedProperties) {
@@ -5109,10 +5767,46 @@ let JupiterDynamicForm = class extends LitElement {
5109
5767
  if (changedProperties.has("financialStatementsTypeAxis")) {
5110
5768
  console.log("🔄 financialStatementsTypeAxis changed:", this.financialStatementsTypeAxis);
5111
5769
  }
5770
+ if ((changedProperties.has("xbrlInput") || changedProperties.has("defaultUnits")) && this.xbrlInput && this.defaultUnits && this.defaultUnits.length > 0) {
5771
+ this._applyDefaultUnitsToDatatypes();
5772
+ }
5112
5773
  if (changedProperties.has("xbrlInput") || changedProperties.has("schema") || changedProperties.has("language") || changedProperties.has("periodStartDate") || changedProperties.has("periodEndDate") || changedProperties.has("financialStatementsTypeAxis")) {
5113
5774
  this._initializeForm();
5114
5775
  }
5115
5776
  }
5777
+ /**
5778
+ * Apply developer-provided default units to datatypes by setting isDefault=true
5779
+ * This allows units to be auto-selected for derived types (e.g., nl-types:monetaryNoDecimals20ItemType)
5780
+ */
5781
+ _applyDefaultUnitsToDatatypes() {
5782
+ var _a;
5783
+ if (!((_a = this.xbrlInput) == null ? void 0 : _a.datatypes) || !this.defaultUnits || this.defaultUnits.length === 0) {
5784
+ return;
5785
+ }
5786
+ console.log("🔧 [DynamicForm] Applying defaultUnits to datatypes:", this.defaultUnits);
5787
+ const datatypesArray = Array.isArray(this.xbrlInput.datatypes) ? this.xbrlInput.datatypes : this.xbrlInput.datatypes.concepts;
5788
+ if (!datatypesArray || datatypesArray.length === 0) {
5789
+ console.warn("⚠️ [DynamicForm] No datatypes found to apply defaults to");
5790
+ return;
5791
+ }
5792
+ this.defaultUnits.forEach((defaultUnitMap) => {
5793
+ Object.entries(defaultUnitMap).forEach(([datatypeId, unitId]) => {
5794
+ const datatype = datatypesArray.find((dt) => dt.type === datatypeId || dt.id === datatypeId);
5795
+ if (datatype && datatype.units && datatype.units.length > 0) {
5796
+ const targetUnit = datatype.units.find((u2) => u2.id === unitId);
5797
+ if (targetUnit) {
5798
+ datatype.units.forEach((u2) => u2.isDefault = false);
5799
+ targetUnit.isDefault = true;
5800
+ console.log(`✅ [DynamicForm] Set isDefault=true for unit "${unitId}" in datatype "${datatypeId}"`);
5801
+ } else {
5802
+ console.warn(`⚠️ [DynamicForm] Unit "${unitId}" not found in datatype "${datatypeId}"`);
5803
+ }
5804
+ } else {
5805
+ console.warn(`⚠️ [DynamicForm] Datatype "${datatypeId}" not found or has no units`);
5806
+ }
5807
+ });
5808
+ });
5809
+ }
5116
5810
  _initializeForm() {
5117
5811
  var _a;
5118
5812
  if (!this._draftStorageService) {
@@ -5155,8 +5849,8 @@ let JupiterDynamicForm = class extends LitElement {
5155
5849
  removable: false
5156
5850
  }
5157
5851
  ];
5158
- } catch (error) {
5159
- console.error("❌ Error building form from XBRL input:", error);
5852
+ } catch (error2) {
5853
+ console.error("❌ Error building form from XBRL input:", error2);
5160
5854
  this._currentSchema = this._getDefaultSchema();
5161
5855
  this._allSections = [];
5162
5856
  this._selectedRoleIds = [];
@@ -5351,9 +6045,9 @@ let JupiterDynamicForm = class extends LitElement {
5351
6045
  if (this._formData[concept.id]) {
5352
6046
  this._preservedFormData[concept.id] = { ...this._formData[concept.id] };
5353
6047
  }
5354
- concept.fields.forEach((field) => {
5355
- if (this._typedMemberData[field.columnId]) {
5356
- this._preservedTypedMemberData[field.columnId] = { ...this._typedMemberData[field.columnId] };
6048
+ concept.fields.forEach((field2) => {
6049
+ if (this._typedMemberData[field2.columnId]) {
6050
+ this._preservedTypedMemberData[field2.columnId] = { ...this._typedMemberData[field2.columnId] };
5357
6051
  }
5358
6052
  });
5359
6053
  if (concept.children) {
@@ -5371,9 +6065,9 @@ let JupiterDynamicForm = class extends LitElement {
5371
6065
  if (this._preservedFormData[concept.id]) {
5372
6066
  this._formData[concept.id] = { ...this._preservedFormData[concept.id] };
5373
6067
  }
5374
- concept.fields.forEach((field) => {
5375
- if (this._preservedTypedMemberData[field.columnId]) {
5376
- this._typedMemberData[field.columnId] = { ...this._preservedTypedMemberData[field.columnId] };
6068
+ concept.fields.forEach((field2) => {
6069
+ if (this._preservedTypedMemberData[field2.columnId]) {
6070
+ this._typedMemberData[field2.columnId] = { ...this._preservedTypedMemberData[field2.columnId] };
5377
6071
  }
5378
6072
  });
5379
6073
  if (concept.children) {
@@ -5408,7 +6102,9 @@ let JupiterDynamicForm = class extends LitElement {
5408
6102
  this._selectedRoleIds,
5409
6103
  this._allSections,
5410
6104
  this._typedMemberData,
5411
- this._periodPreferences
6105
+ this._periodPreferences,
6106
+ this._periodData,
6107
+ this._unitData
5412
6108
  );
5413
6109
  this._draftStorageService.saveDraft(currentFormData, currentMetadata);
5414
6110
  console.log("✅ Current form data saved to draft storage");
@@ -5418,8 +6114,8 @@ let JupiterDynamicForm = class extends LitElement {
5418
6114
  console.log("📥 Restoring form data from draft after reinitialization...");
5419
6115
  this._loadDraftIfExists().then(() => {
5420
6116
  console.log("✅ Form data restored successfully after reinitialization");
5421
- }).catch((error) => {
5422
- console.error("❌ Error restoring form data after reinitialization:", error);
6117
+ }).catch((error2) => {
6118
+ console.error("❌ Error restoring form data after reinitialization:", error2);
5423
6119
  });
5424
6120
  } else {
5425
6121
  this._applyRoleFilter();
@@ -5444,15 +6140,15 @@ let JupiterDynamicForm = class extends LitElement {
5444
6140
  return;
5445
6141
  for (const section2 of schema.sections) {
5446
6142
  for (const concept of section2.concepts) {
5447
- for (const field of concept.fields) {
5448
- const value = (_a = this._formData[concept.id]) == null ? void 0 : _a[field.columnId];
6143
+ for (const field2 of concept.fields) {
6144
+ const value = (_a = this._formData[concept.id]) == null ? void 0 : _a[field2.columnId];
5449
6145
  const fieldErrors = FormValidator.validateField(
5450
- field.id,
6146
+ field2.id,
5451
6147
  concept.id,
5452
- field.columnId,
6148
+ field2.columnId,
5453
6149
  value,
5454
- field.type,
5455
- field.validation || []
6150
+ field2.type,
6151
+ field2.validation || []
5456
6152
  );
5457
6153
  errors.push(...fieldErrors);
5458
6154
  }
@@ -5484,8 +6180,8 @@ let JupiterDynamicForm = class extends LitElement {
5484
6180
  _handlePeriodChange(event) {
5485
6181
  console.log(`🎯 [DynamicForm] _handlePeriodChange called with event:`, event);
5486
6182
  console.log(`🎯 [DynamicForm] Event detail:`, event.detail);
5487
- const { conceptId, columnId, periodType, periodStartDate, periodEndDate, periodInstantDate } = event.detail;
5488
- console.log(`📅 Period change received: conceptId=${conceptId}, columnId=${columnId}, periodType=${periodType}, startDate=${periodStartDate}, endDate=${periodEndDate}, instantDate=${periodInstantDate}`);
6183
+ const { conceptId, columnId, periodType, periodStartDate, periodEndDate, periodInstantDate, unit } = event.detail;
6184
+ console.log(`📅 Period change received: conceptId=${conceptId}, columnId=${columnId}, periodType=${periodType}, startDate=${periodStartDate}, endDate=${periodEndDate}, instantDate=${periodInstantDate}, unit=${unit}`);
5489
6185
  const updatedPeriodData = { ...this._periodData };
5490
6186
  if (!updatedPeriodData[conceptId]) {
5491
6187
  updatedPeriodData[conceptId] = {};
@@ -5501,9 +6197,37 @@ let JupiterDynamicForm = class extends LitElement {
5501
6197
  this._periodData = updatedPeriodData;
5502
6198
  console.log(`💾 Period data stored for [${conceptId}][${columnId}]:`, this._periodData[conceptId][columnId]);
5503
6199
  console.log(`📦 Full period data state:`, JSON.stringify(this._periodData, null, 2));
6200
+ if (unit) {
6201
+ this._storeUnit(conceptId, columnId, unit);
6202
+ }
5504
6203
  this._dirty = true;
5505
6204
  this.requestUpdate();
5506
6205
  }
6206
+ _handleUnitChange(event) {
6207
+ console.log(`🏷️ [DynamicForm] _handleUnitChange called with event:`, event);
6208
+ console.log(`🏷️ [DynamicForm] Event detail:`, event.detail);
6209
+ const { conceptId, columnId, unit } = event.detail;
6210
+ console.log(`🏷️ Unit change received: conceptId=${conceptId}, columnId=${columnId}, unit=${unit}`);
6211
+ this._storeUnit(conceptId, columnId, unit);
6212
+ this._dirty = true;
6213
+ this.requestUpdate();
6214
+ }
6215
+ _storeUnit(conceptId, columnId, unit) {
6216
+ console.log(`🔧 [_storeUnit] Called with conceptId=${conceptId}, columnId=${columnId}, unit=${unit}`);
6217
+ console.log(`🔧 [_storeUnit] Current _unitData before update:`, JSON.stringify(this._unitData, null, 2));
6218
+ const updatedUnitData = { ...this._unitData };
6219
+ if (!updatedUnitData[conceptId]) {
6220
+ console.log(`🔧 [_storeUnit] Creating new entry for conceptId: ${conceptId}`);
6221
+ updatedUnitData[conceptId] = {};
6222
+ }
6223
+ updatedUnitData[conceptId] = {
6224
+ ...updatedUnitData[conceptId],
6225
+ [columnId]: unit
6226
+ };
6227
+ this._unitData = updatedUnitData;
6228
+ console.log(`💾 [_storeUnit] Unit data stored for [${conceptId}][${columnId}]:`, this._unitData[conceptId][columnId]);
6229
+ console.log(`📦 [_storeUnit] Full unit data state after update:`, JSON.stringify(this._unitData, null, 2));
6230
+ }
5507
6231
  /**
5508
6232
  * Generate a unique concept key that includes section context
5509
6233
  */
@@ -5533,6 +6257,164 @@ let JupiterDynamicForm = class extends LitElement {
5533
6257
  bubbles: true
5534
6258
  }));
5535
6259
  }
6260
+ _handleFieldBlur(event) {
6261
+ var _a;
6262
+ console.log(`🟧 [DynamicForm] _handleFieldBlur received event:`, event);
6263
+ console.log(`🟧 [DynamicForm] Event detail:`, event.detail);
6264
+ const { fieldId, conceptId, columnId, xbrlValidationErrors } = event.detail;
6265
+ console.log(`🟧 [DynamicForm] Extracted - fieldId: ${fieldId}, conceptId: ${conceptId}, columnId: ${columnId}`);
6266
+ console.log(`🟧 [DynamicForm] xbrlValidationErrors:`, xbrlValidationErrors);
6267
+ let sectionId = "";
6268
+ const path = event.composedPath();
6269
+ console.log(`🟧 [DynamicForm] Event path length: ${path.length}`);
6270
+ for (const element of path) {
6271
+ const el = element;
6272
+ if (el.tagName === "JUPITER-FORM-SECTION") {
6273
+ sectionId = el.getAttribute("section-id") || "";
6274
+ console.log(`🟧 [DynamicForm] Found section element with id: ${sectionId}`);
6275
+ break;
6276
+ }
6277
+ }
6278
+ console.log(`🟧 [DynamicForm] Found sectionId: ${sectionId}`);
6279
+ console.log(`🟧 [DynamicForm] Processing errors - has errors: ${xbrlValidationErrors && xbrlValidationErrors.length > 0}`);
6280
+ if (xbrlValidationErrors && xbrlValidationErrors.length > 0) {
6281
+ console.log(`🟧 [DynamicForm] Adding/updating error for fieldId: ${fieldId}, sectionId: ${sectionId}`);
6282
+ const value = ((_a = this._formData[conceptId]) == null ? void 0 : _a[columnId]) || "";
6283
+ const existingIndex = this._xbrlFormErrors.findIndex(
6284
+ (e2) => e2.fieldId === fieldId && e2.sectionId === sectionId
6285
+ );
6286
+ const newError = {
6287
+ sectionId,
6288
+ fieldId,
6289
+ conceptId,
6290
+ columnId,
6291
+ value,
6292
+ errors: xbrlValidationErrors
6293
+ };
6294
+ console.log(`🟧 [DynamicForm] New error object:`, newError);
6295
+ console.log(`🟧 [DynamicForm] Existing index: ${existingIndex}`);
6296
+ if (existingIndex >= 0) {
6297
+ this._xbrlFormErrors = [
6298
+ ...this._xbrlFormErrors.slice(0, existingIndex),
6299
+ newError,
6300
+ ...this._xbrlFormErrors.slice(existingIndex + 1)
6301
+ ];
6302
+ console.log(`🟧 [DynamicForm] Updated existing error at index ${existingIndex}`);
6303
+ } else {
6304
+ this._xbrlFormErrors = [...this._xbrlFormErrors, newError];
6305
+ console.log(`🟧 [DynamicForm] Added new error`);
6306
+ }
6307
+ } else {
6308
+ console.log(`🟧 [DynamicForm] Removing error (if exists) for fieldId: ${fieldId}, sectionId: ${sectionId}`);
6309
+ const beforeLength = this._xbrlFormErrors.length;
6310
+ this._xbrlFormErrors = this._xbrlFormErrors.filter(
6311
+ (e2) => !(e2.fieldId === fieldId && e2.sectionId === sectionId)
6312
+ );
6313
+ console.log(`🟧 [DynamicForm] Removed ${beforeLength - this._xbrlFormErrors.length} errors`);
6314
+ }
6315
+ console.log(`🔍 [Validation] Total errors: ${this._xbrlFormErrors.length}`, this._xbrlFormErrors);
6316
+ }
6317
+ _getSectionTitle(sectionId) {
6318
+ console.log(`🔍 [_getSectionTitle] Looking for sectionId: "${sectionId}"`);
6319
+ console.log(`🔍 [_getSectionTitle] Available sections:`, this._allSections.map((s2) => ({ id: s2.id, title: s2.title })));
6320
+ const section2 = this._allSections.find((s2) => s2.id === sectionId);
6321
+ const result = (section2 == null ? void 0 : section2.title) || sectionId || "(Unknown Section)";
6322
+ console.log(`🔍 [_getSectionTitle] Result: "${result}"`);
6323
+ return result;
6324
+ }
6325
+ async _handleErrorFieldClick(conceptId, columnId, sectionId) {
6326
+ var _a, _b, _c, _d;
6327
+ console.log(`🎯 [Error Click] Attempting to focus field: ${conceptId}__${columnId} in section: ${sectionId}`);
6328
+ this._showErrorPopup = false;
6329
+ this.requestUpdate();
6330
+ await this.updateComplete;
6331
+ if (this.display === "sidePanel" && this._activeSidePanelRoleId !== sectionId) {
6332
+ console.log(`🔀 Switching to section: ${sectionId} (currently on: ${this._activeSidePanelRoleId})`);
6333
+ this._activeSidePanelRoleId = sectionId;
6334
+ this.requestUpdate();
6335
+ await this.updateComplete;
6336
+ await new Promise((resolve) => setTimeout(resolve, 500));
6337
+ }
6338
+ const sectionElements = (_a = this.shadowRoot) == null ? void 0 : _a.querySelectorAll("jupiter-form-section");
6339
+ let targetSection = null;
6340
+ sectionElements == null ? void 0 : sectionElements.forEach((sectionEl) => {
6341
+ var _a2;
6342
+ if (((_a2 = sectionEl.section) == null ? void 0 : _a2.id) === sectionId) {
6343
+ targetSection = sectionEl;
6344
+ }
6345
+ });
6346
+ if (!targetSection) {
6347
+ console.warn(`⚠️ Section not found: ${sectionId}`);
6348
+ return;
6349
+ }
6350
+ console.log(`✅ Found section element:`, targetSection);
6351
+ if ((_b = targetSection.section) == null ? void 0 : _b.collapsed) {
6352
+ console.log(`📂 Expanding collapsed section`);
6353
+ targetSection.section.collapsed = false;
6354
+ targetSection.requestUpdate();
6355
+ await targetSection.updateComplete;
6356
+ await new Promise((resolve) => setTimeout(resolve, 500));
6357
+ } else {
6358
+ await targetSection.updateComplete;
6359
+ await new Promise((resolve) => setTimeout(resolve, 100));
6360
+ }
6361
+ console.log(`🔍 Section shadow DOM exists: ${!!targetSection.shadowRoot}`);
6362
+ if (targetSection.shadowRoot) {
6363
+ console.log(`🔍 Shadow DOM innerHTML length: ${((_c = targetSection.shadowRoot.innerHTML) == null ? void 0 : _c.length) || 0}`);
6364
+ const allElements = targetSection.shadowRoot.querySelectorAll("*");
6365
+ console.log(`🔍 Total elements in shadow DOM: ${allElements.length}`);
6366
+ const customElements2 = Array.from(allElements).filter((el) => {
6367
+ const element = el;
6368
+ return !!(element.tagName && element.tagName.includes("-"));
6369
+ });
6370
+ console.log(`🔍 Custom elements found:`, customElements2.map((el) => el.tagName).join(", "));
6371
+ }
6372
+ const fieldId = `${conceptId}_${columnId}_field`;
6373
+ console.log(`🔍 Looking for input with fieldId: ${fieldId}`);
6374
+ console.log(`🔍 Looking for field with conceptId: ${conceptId} AND columnId: ${columnId}`);
6375
+ const conceptTrees = (_d = targetSection.shadowRoot) == null ? void 0 : _d.querySelectorAll("jupiter-concept-tree");
6376
+ let targetInput = null;
6377
+ console.log(`🔍 Found ${(conceptTrees == null ? void 0 : conceptTrees.length) || 0} concept-tree elements`);
6378
+ if (conceptTrees) {
6379
+ conceptTrees.forEach((conceptTree, treeIndex) => {
6380
+ var _a2;
6381
+ if (targetInput)
6382
+ return;
6383
+ const formFieldsInTree = (_a2 = conceptTree.shadowRoot) == null ? void 0 : _a2.querySelectorAll("jupiter-form-field");
6384
+ console.log(`🔍 Concept tree ${treeIndex}: Found ${(formFieldsInTree == null ? void 0 : formFieldsInTree.length) || 0} form-field elements`);
6385
+ formFieldsInTree == null ? void 0 : formFieldsInTree.forEach((fieldEl, fieldIndex) => {
6386
+ var _a3;
6387
+ if (targetInput)
6388
+ return;
6389
+ console.log(` Field ${fieldIndex}: conceptId=${fieldEl.conceptId}, columnId=${fieldEl.columnId}`);
6390
+ if (fieldEl.conceptId === conceptId && fieldEl.columnId === columnId) {
6391
+ const inputEl = (_a3 = fieldEl.shadowRoot) == null ? void 0 : _a3.querySelector("input, textarea");
6392
+ console.log(` -> Matched! Input element found: ${!!inputEl}`);
6393
+ if (inputEl) {
6394
+ targetInput = inputEl;
6395
+ console.log(`✅ Found input element in form-field`);
6396
+ }
6397
+ }
6398
+ });
6399
+ });
6400
+ }
6401
+ if (!targetInput) {
6402
+ console.warn(`⚠️ Input field not found for: ${fieldId}`);
6403
+ return;
6404
+ }
6405
+ const input = targetInput;
6406
+ targetSection.scrollIntoView({ behavior: "smooth", block: "start" });
6407
+ await new Promise((resolve) => setTimeout(resolve, 300));
6408
+ input.focus();
6409
+ if (input.tagName === "INPUT" || input.tagName === "TEXTAREA") {
6410
+ input.select();
6411
+ }
6412
+ input.style.boxShadow = "0 0 0 3px rgba(220, 38, 38, 0.5)";
6413
+ setTimeout(() => {
6414
+ input.style.boxShadow = "";
6415
+ }, 2e3);
6416
+ console.log(`✅ Successfully focused field: ${conceptId}__${columnId}`);
6417
+ }
5536
6418
  _handleSectionExpand(event) {
5537
6419
  this.dispatchEvent(new CustomEvent("section-expand", {
5538
6420
  detail: event.detail,
@@ -5798,7 +6680,7 @@ let JupiterDynamicForm = class extends LitElement {
5798
6680
  delete this._formData[concept.id][columnId];
5799
6681
  }
5800
6682
  if (concept.fields) {
5801
- concept.fields = concept.fields.filter((field) => field.columnId !== columnId);
6683
+ concept.fields = concept.fields.filter((field2) => field2.columnId !== columnId);
5802
6684
  }
5803
6685
  if (concept.children) {
5804
6686
  this._removeColumnDataFromConcepts(concept.children, columnId);
@@ -5809,7 +6691,8 @@ let JupiterDynamicForm = class extends LitElement {
5809
6691
  if (concept.abstract) {
5810
6692
  return false;
5811
6693
  }
5812
- if (concept.periodType) {
6694
+ const isDimensionColumn = request.selectedDimensions && request.selectedDimensions.length > 0;
6695
+ if (!isDimensionColumn && concept.periodType) {
5813
6696
  if (request.periodType === "instant" && concept.periodType !== "instant") {
5814
6697
  return false;
5815
6698
  }
@@ -5833,9 +6716,9 @@ let JupiterDynamicForm = class extends LitElement {
5833
6716
  var _a;
5834
6717
  if (this._shouldCreateFieldForConcept(concept, request)) {
5835
6718
  const existingField = (_a = concept.fields) == null ? void 0 : _a[0];
5836
- let field;
6719
+ let field2;
5837
6720
  if (existingField) {
5838
- field = {
6721
+ field2 = {
5839
6722
  id: `${concept.id}_${columnId}`,
5840
6723
  conceptId: concept.id,
5841
6724
  columnId,
@@ -5848,13 +6731,15 @@ let JupiterDynamicForm = class extends LitElement {
5848
6731
  defaultValue: existingField.defaultValue,
5849
6732
  periodType: concept.periodType,
5850
6733
  // Add periodType from concept
6734
+ conceptType: concept.type,
6735
+ // CRITICAL: Include conceptType for XBRL validation
5851
6736
  // Set period dates from the add column request
5852
6737
  periodStartDate: request.periodType === "instant" ? request.instantDate : request.startDate,
5853
6738
  periodEndDate: request.periodType === "instant" ? request.instantDate : request.endDate,
5854
6739
  periodInstantDate: concept.periodType === "instant" ? request.instantDate || request.startDate : void 0
5855
6740
  };
5856
6741
  } else {
5857
- field = {
6742
+ field2 = {
5858
6743
  id: `${concept.id}_${columnId}`,
5859
6744
  conceptId: concept.id,
5860
6745
  columnId,
@@ -5867,6 +6752,8 @@ let JupiterDynamicForm = class extends LitElement {
5867
6752
  defaultValue: "",
5868
6753
  periodType: concept.periodType,
5869
6754
  // Add periodType from concept
6755
+ conceptType: concept.type,
6756
+ // CRITICAL: Include conceptType for XBRL validation
5870
6757
  // Set period dates from the add column request
5871
6758
  periodStartDate: request.periodType === "instant" ? request.instantDate : request.startDate,
5872
6759
  periodEndDate: request.periodType === "instant" ? request.instantDate : request.endDate,
@@ -5876,7 +6763,7 @@ let JupiterDynamicForm = class extends LitElement {
5876
6763
  if (!concept.fields) {
5877
6764
  concept.fields = [];
5878
6765
  }
5879
- concept.fields.push(field);
6766
+ concept.fields.push(field2);
5880
6767
  }
5881
6768
  if (concept.children) {
5882
6769
  this._replicateFieldsForSection(concept.children, columnId, request, formBuilder);
@@ -5915,6 +6802,10 @@ let JupiterDynamicForm = class extends LitElement {
5915
6802
  this._validateForm();
5916
6803
  const submissionData = this._generateSubmissionData();
5917
6804
  console.log("📊 Form Submission Data:", JSON.stringify(submissionData, null, 2));
6805
+ console.log("📊 Submission Data Summary:");
6806
+ submissionData.forEach((entry, index) => {
6807
+ console.log(` [${index}] conceptId: ${entry.conceptId}, columnId: ${entry.columnId}, value: ${entry.value}, unit: ${entry.unit || "none"}`);
6808
+ });
5918
6809
  this.dispatchEvent(new CustomEvent("form-submit", {
5919
6810
  detail: {
5920
6811
  data: this._formData,
@@ -5927,12 +6818,23 @@ let JupiterDynamicForm = class extends LitElement {
5927
6818
  console.log("✅ Form submit event dispatched");
5928
6819
  }
5929
6820
  _handleSaveDraft() {
6821
+ console.log(`🔵 [Save Draft] Checking for errors...`);
6822
+ console.log(`🔵 [Save Draft] _xbrlFormErrors.length: ${this._xbrlFormErrors.length}`);
6823
+ console.log(`🔵 [Save Draft] _xbrlFormErrors:`, this._xbrlFormErrors);
6824
+ if (this._xbrlFormErrors.length > 0) {
6825
+ console.log("❌ [Save Draft] Cannot save - validation errors present:", this._xbrlFormErrors);
6826
+ this._showErrorPopup = true;
6827
+ this.requestUpdate();
6828
+ return;
6829
+ }
6830
+ console.log(`✅ [Save Draft] No validation errors, proceeding with save...`);
5930
6831
  console.log("💾 Raw form data before submission generation:", this._formData);
6832
+ console.log("🏷️ Unit data before submission generation:", this._unitData);
5931
6833
  const draftData = this._generateSubmissionData();
5932
6834
  console.log("📤 Generated submission data:", draftData);
5933
6835
  console.log("📊 Submission data breakdown:");
5934
6836
  draftData.forEach((entry, index) => {
5935
- console.log(` [${index}] conceptId: ${entry.conceptId}, columnId: ${entry.columnId}, value: ${entry.value}`);
6837
+ console.log(` [${index}] conceptId: ${entry.conceptId}, columnId: ${entry.columnId}, value: ${entry.value}, unit: ${entry.unit || "none"}`);
5936
6838
  });
5937
6839
  const metadata = this._draftStorageService.createMetadataSnapshot(
5938
6840
  this.periodStartDate,
@@ -5942,7 +6844,8 @@ let JupiterDynamicForm = class extends LitElement {
5942
6844
  this._allSections,
5943
6845
  this._typedMemberData,
5944
6846
  this._periodPreferences,
5945
- this._periodData
6847
+ this._periodData,
6848
+ this._unitData
5946
6849
  );
5947
6850
  const saved = this._draftStorageService.saveDraft(draftData, metadata);
5948
6851
  this.dynaformsFacts = draftData;
@@ -6046,6 +6949,10 @@ let JupiterDynamicForm = class extends LitElement {
6046
6949
  this._periodData = metadata.periodData;
6047
6950
  console.log("🔄 Restored custom field-level period data:", Object.keys(this._periodData).length, "concepts");
6048
6951
  }
6952
+ if (metadata.unitData) {
6953
+ this._unitData = metadata.unitData;
6954
+ console.log("🔄 Restored custom field-level unit data:", Object.keys(this._unitData).length, "concepts");
6955
+ }
6049
6956
  if (metadata.periodPreferences) {
6050
6957
  this._periodPreferences = metadata.periodPreferences;
6051
6958
  console.log("🔄 Restored period preferences (including previous year settings):", this._periodPreferences);
@@ -6078,8 +6985,9 @@ let JupiterDynamicForm = class extends LitElement {
6078
6985
  }
6079
6986
  const restoredFormData = {};
6080
6987
  const restoredPeriodData = {};
6988
+ const restoredUnitData = {};
6081
6989
  formData.forEach((entry) => {
6082
- let { conceptId, value, columnId, period } = entry;
6990
+ let { conceptId, value, columnId, period, unit } = entry;
6083
6991
  if (!columnId && period) {
6084
6992
  columnId = this._inferColumnIdFromPeriod(period, conceptId);
6085
6993
  if (!columnId) {
@@ -6111,6 +7019,13 @@ let JupiterDynamicForm = class extends LitElement {
6111
7019
  console.log(`📅 [Restore Period] Extracted duration dates for ${conceptIdToUse}/${columnId}: ${period.startDate} - ${period.endDate}`);
6112
7020
  }
6113
7021
  }
7022
+ if (unit) {
7023
+ if (!restoredUnitData[conceptIdToUse]) {
7024
+ restoredUnitData[conceptIdToUse] = {};
7025
+ }
7026
+ restoredUnitData[conceptIdToUse][columnId] = unit;
7027
+ console.log(`🏷️ [Restore Unit] Extracted unit for ${conceptIdToUse}/${columnId}: ${unit}`);
7028
+ }
6114
7029
  });
6115
7030
  this._formData = { ...this._formData, ...restoredFormData };
6116
7031
  console.log(`🔄 Restored ${Object.keys(restoredFormData).length} concepts with data`);
@@ -6121,6 +7036,13 @@ let JupiterDynamicForm = class extends LitElement {
6121
7036
  };
6122
7037
  console.log(`📅 [Period Restore] Merged period data: ${Object.keys(this._periodData).length} concepts with custom periods`);
6123
7038
  console.log(`📅 [Period Restore] Full _periodData after merge:`, JSON.stringify(this._periodData, null, 2));
7039
+ this._unitData = {
7040
+ ...this._unitData,
7041
+ ...metadata.unitData || {},
7042
+ ...restoredUnitData
7043
+ };
7044
+ console.log(`🏷️ [Unit Restore] Merged unit data: ${Object.keys(this._unitData).length} concepts with custom units`);
7045
+ console.log(`🏷️ [Unit Restore] Full _unitData after merge:`, JSON.stringify(this._unitData, null, 2));
6124
7046
  if (this._selectedRoleIds.length > 0) {
6125
7047
  this._applyRoleFilter();
6126
7048
  }
@@ -6247,6 +7169,7 @@ let JupiterDynamicForm = class extends LitElement {
6247
7169
  columnsBySection.get(col.sectionId).push(col);
6248
7170
  });
6249
7171
  this._allSections.forEach((section2) => {
7172
+ var _a;
6250
7173
  const savedColumns = columnsBySection.get(section2.id);
6251
7174
  if (savedColumns) {
6252
7175
  section2.columns = savedColumns.map((col) => {
@@ -6258,11 +7181,22 @@ let JupiterDynamicForm = class extends LitElement {
6258
7181
  periodEndDate: col.endDate || col.date,
6259
7182
  dimensionData: col.dimensionData,
6260
7183
  order: 0,
6261
- removable: col.columnId !== "duration" && col.columnId !== "instant"
7184
+ removable: col.columnId !== "duration" && col.columnId !== "instant",
7185
+ periodType: col.periodType
7186
+ // CRITICAL: Preserve explicit period type
6262
7187
  };
6263
- console.log(`📅 [Draft Restore] Restoring column ${col.columnId}: startDate=${column2.periodStartDate}, endDate=${column2.periodEndDate}`);
7188
+ console.log(`📅 [Draft Restore] Restoring column ${col.columnId}: startDate=${column2.periodStartDate}, endDate=${column2.periodEndDate}, periodType=${column2.periodType}`);
6264
7189
  return column2;
6265
7190
  });
7191
+ if (((_a = this.xbrlInput) == null ? void 0 : _a.datatypes) && !section2.datatypes) {
7192
+ const datatypesArray = Array.isArray(this.xbrlInput.datatypes) ? this.xbrlInput.datatypes : this.xbrlInput.datatypes.concepts || [];
7193
+ section2.datatypes = datatypesArray;
7194
+ console.log(`✅ [Draft Restore] Attached ${datatypesArray.length} datatypes to section ${section2.id}`);
7195
+ } else if (section2.datatypes) {
7196
+ console.log(`ℹ️ [Draft Restore] Section ${section2.id} already has ${section2.datatypes.length} datatypes`);
7197
+ } else {
7198
+ console.warn(`⚠️ [Draft Restore] No datatypes available for section ${section2.id}`);
7199
+ }
6266
7200
  this._regenerateFieldsForSection(section2);
6267
7201
  console.log(` └─ Restored ${savedColumns.length} columns for section ${section2.id}`);
6268
7202
  }
@@ -6291,11 +7225,21 @@ let JupiterDynamicForm = class extends LitElement {
6291
7225
  }
6292
7226
  });
6293
7227
  this._allSections.forEach((section2) => {
7228
+ var _a;
6294
7229
  const customColumnsForSection = columnsBySection.get(section2.id);
6295
7230
  if (customColumnsForSection && customColumnsForSection.length > 0) {
6296
7231
  if (!section2.columns) {
6297
7232
  section2.columns = [];
6298
7233
  }
7234
+ if (((_a = this.xbrlInput) == null ? void 0 : _a.datatypes) && !section2.datatypes) {
7235
+ const datatypesArray = Array.isArray(this.xbrlInput.datatypes) ? this.xbrlInput.datatypes : this.xbrlInput.datatypes.concepts || [];
7236
+ section2.datatypes = datatypesArray;
7237
+ console.log(`✅ [Merge Custom] Attached ${datatypesArray.length} datatypes to section ${section2.id}`);
7238
+ } else if (section2.datatypes) {
7239
+ console.log(`ℹ️ [Merge Custom] Section ${section2.id} already has ${section2.datatypes.length} datatypes`);
7240
+ } else {
7241
+ console.warn(`⚠️ [Merge Custom] No datatypes available for section ${section2.id}`);
7242
+ }
6299
7243
  customColumnsForSection.forEach((col) => {
6300
7244
  console.log(`📅 [Merge Custom Column] Column ${col.columnId}: col.startDate=${col.startDate}, col.endDate=${col.endDate}, col.date=${col.date}, col.periodType=${col.periodType}`);
6301
7245
  const existingColumn = section2.columns.find((c2) => c2.id === col.columnId);
@@ -6308,9 +7252,11 @@ let JupiterDynamicForm = class extends LitElement {
6308
7252
  periodEndDate: col.endDate || col.date,
6309
7253
  dimensionData: col.dimensionData,
6310
7254
  order: section2.columns.length,
6311
- removable: true
7255
+ removable: true,
7256
+ periodType: col.periodType
7257
+ // CRITICAL: Preserve explicit period type
6312
7258
  };
6313
- console.log(`📅 [New Column Created] Column ${newColumn.id}: periodStartDate=${newColumn.periodStartDate}, periodEndDate=${newColumn.periodEndDate}`);
7259
+ console.log(`📅 [New Column Created] Column ${newColumn.id}: periodStartDate=${newColumn.periodStartDate}, periodEndDate=${newColumn.periodEndDate}, periodType=${newColumn.periodType}`);
6314
7260
  section2.columns.push(newColumn);
6315
7261
  console.log(` └─ Added custom column ${col.columnId} to section ${section2.id}`);
6316
7262
  }
@@ -6340,20 +7286,20 @@ let JupiterDynamicForm = class extends LitElement {
6340
7286
  if (this._periodData[concept.id]) {
6341
7287
  const conceptPeriodData = this._periodData[concept.id];
6342
7288
  if (concept.fields) {
6343
- concept.fields.forEach((field) => {
6344
- const customPeriod = conceptPeriodData[field.columnId];
7289
+ concept.fields.forEach((field2) => {
7290
+ const customPeriod = conceptPeriodData[field2.columnId];
6345
7291
  if (customPeriod) {
6346
7292
  if (customPeriod.startDate) {
6347
- field.periodStartDate = customPeriod.startDate;
7293
+ field2.periodStartDate = customPeriod.startDate;
6348
7294
  }
6349
7295
  if (customPeriod.endDate) {
6350
- field.periodEndDate = customPeriod.endDate;
7296
+ field2.periodEndDate = customPeriod.endDate;
6351
7297
  }
6352
7298
  if (customPeriod.instantDate) {
6353
- field.periodInstantDate = customPeriod.instantDate;
7299
+ field2.periodInstantDate = customPeriod.instantDate;
6354
7300
  }
6355
7301
  appliedCount++;
6356
- console.log(`✅ [Apply Period] Updated field ${concept.id}/${field.columnId}: start=${field.periodStartDate}, end=${field.periodEndDate}, instant=${field.periodInstantDate}`);
7302
+ console.log(`✅ [Apply Period] Updated field ${concept.id}/${field2.columnId}: start=${field2.periodStartDate}, end=${field2.periodEndDate}, instant=${field2.periodInstantDate}`);
6357
7303
  }
6358
7304
  });
6359
7305
  }
@@ -6392,7 +7338,10 @@ let JupiterDynamicForm = class extends LitElement {
6392
7338
  const columnPeriodType = this._inferColumnPeriodType(column2);
6393
7339
  if (concept.abstract)
6394
7340
  return;
6395
- const shouldSkipPeriodCheck = !columnPeriodType || column2.id === "duration" || column2.id === "default";
7341
+ const isCustomColumn = column2.id.startsWith("col-");
7342
+ const isDimensionColumn = column2.id.startsWith("duration_") || column2.id.startsWith("instant_");
7343
+ const isMixedSection = section2.showPeriodControl === true;
7344
+ const shouldSkipPeriodCheck = !columnPeriodType || column2.id === "duration" || column2.id === "default" || isCustomColumn && isMixedSection || isDimensionColumn;
6396
7345
  if (!shouldSkipPeriodCheck && conceptPeriodType && columnPeriodType) {
6397
7346
  if (conceptPeriodType !== columnPeriodType) {
6398
7347
  console.log(`⏭️ [Field Regeneration] Skipping field for ${concept.id} in column ${column2.id}: conceptPeriodType=${conceptPeriodType}, columnPeriodType=${columnPeriodType}`);
@@ -6407,6 +7356,8 @@ let JupiterDynamicForm = class extends LitElement {
6407
7356
  label: concept.label,
6408
7357
  periodType: conceptPeriodType,
6409
7358
  // Add periodType from concept
7359
+ conceptType: concept.type,
7360
+ // CRITICAL: Include conceptType for XBRL validation
6410
7361
  periodStartDate: column2.periodStartDate,
6411
7362
  periodEndDate: column2.periodEndDate,
6412
7363
  periodInstantDate: conceptPeriodType === "instant" ? column2.periodEndDate || column2.periodStartDate : void 0
@@ -6456,6 +7407,9 @@ let JupiterDynamicForm = class extends LitElement {
6456
7407
  return true;
6457
7408
  }
6458
7409
  _inferColumnPeriodType(column2) {
7410
+ if (column2.periodType) {
7411
+ return column2.periodType;
7412
+ }
6459
7413
  if (column2.periodStartDate && column2.periodEndDate) {
6460
7414
  return column2.periodStartDate === column2.periodEndDate ? "instant" : "duration";
6461
7415
  }
@@ -6533,17 +7487,18 @@ let JupiterDynamicForm = class extends LitElement {
6533
7487
  return null;
6534
7488
  }
6535
7489
  _addConceptDataToSubmission(concept, columnId, value, submissionData, section2) {
6536
- var _a, _b;
6537
- const field = concept.fields.find((f2) => f2.columnId === columnId);
6538
- if (!field)
7490
+ var _a, _b, _c;
7491
+ const field2 = concept.fields.find((f2) => f2.columnId === columnId);
7492
+ if (!field2)
6539
7493
  return;
6540
7494
  const isInstant = concept.periodType === "instant";
6541
7495
  const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[columnId];
7496
+ const fieldUnit = (_b = this._unitData[concept.id]) == null ? void 0 : _b[columnId];
6542
7497
  const column2 = this._findColumnByIdInAllSections(columnId);
6543
- console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}`);
6544
- const periodStartDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field.periodStartDate || this.periodStartDate;
6545
- const periodEndDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field.periodEndDate || this.periodEndDate;
6546
- const periodInstantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || field.periodInstantDate || periodEndDate || periodStartDate;
7498
+ console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Unit: ${fieldUnit || "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}`);
7499
+ const periodStartDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field2.periodStartDate || this.periodStartDate;
7500
+ const periodEndDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodEndDate || this.periodEndDate;
7501
+ const periodInstantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || field2.periodInstantDate || periodEndDate || periodStartDate;
6547
7502
  const entry = {
6548
7503
  conceptId: concept.originalConceptId || concept.id,
6549
7504
  columnId,
@@ -6556,9 +7511,14 @@ let JupiterDynamicForm = class extends LitElement {
6556
7511
  }
6557
7512
  }
6558
7513
  };
6559
- if ((_b = column2 == null ? void 0 : column2.dimensionData) == null ? void 0 : _b.memberLabel) {
7514
+ if (fieldUnit) {
7515
+ entry.unit = fieldUnit;
7516
+ console.log(`✅ [Submission] Adding unit to entry: ${fieldUnit} for ${concept.id}/${columnId}`);
7517
+ }
7518
+ if ((_c = column2 == null ? void 0 : column2.dimensionData) == null ? void 0 : _c.memberLabel) {
6560
7519
  entry.dimension = column2.dimensionData.memberLabel;
6561
7520
  }
7521
+ console.log(`📤 [Submission Entry] Created entry:`, JSON.stringify(entry, null, 2));
6562
7522
  submissionData.push(entry);
6563
7523
  }
6564
7524
  _findColumnByIdInAllSections(columnId) {
@@ -6681,27 +7641,27 @@ let JupiterDynamicForm = class extends LitElement {
6681
7641
  console.warn(`[DUPLICATE DEBUG] Processing concept ${concept.originalConceptId || concept.id} in target role`);
6682
7642
  if (concept.fields) {
6683
7643
  console.warn(`[DUPLICATE DEBUG] Concept has ${concept.fields.length} fields`);
6684
- concept.fields.forEach((field, index) => {
7644
+ concept.fields.forEach((field2, index) => {
6685
7645
  var _a;
6686
- console.warn(`[DUPLICATE DEBUG] Field ${index}: columnId=${field.columnId}, current value=${(_a = this._formData[concept.id]) == null ? void 0 : _a[field.columnId]}`);
7646
+ console.warn(`[DUPLICATE DEBUG] Field ${index}: columnId=${field2.columnId}, current value=${(_a = this._formData[concept.id]) == null ? void 0 : _a[field2.columnId]}`);
6687
7647
  });
6688
7648
  }
6689
7649
  }
6690
7650
  if (concept.fields && concept.fields.length > 1) {
6691
- concept.fields.forEach((field, index) => {
7651
+ concept.fields.forEach((field2, index) => {
6692
7652
  });
6693
7653
  }
6694
7654
  if (concept.fields && concept.fields.length > 0) {
6695
- concept.fields.forEach((field) => {
6696
- var _a, _b, _c;
7655
+ concept.fields.forEach((field2) => {
7656
+ var _a, _b, _c, _d;
6697
7657
  const conceptData = this._formData[concept.id];
6698
- const fieldValue = conceptData == null ? void 0 : conceptData[field.columnId];
7658
+ const fieldValue = conceptData == null ? void 0 : conceptData[field2.columnId];
6699
7659
  if (fieldValue !== void 0 && fieldValue !== null && fieldValue !== "") {
6700
- const column2 = this._findColumnByIdInSection(field.columnId, section2);
6701
- const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[field.columnId];
7660
+ const column2 = this._findColumnByIdInSection(field2.columnId, section2);
7661
+ const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[field2.columnId];
6702
7662
  const submissionEntry = {
6703
7663
  conceptId: concept.id,
6704
- columnId: field.columnId,
7664
+ columnId: field2.columnId,
6705
7665
  // CRITICAL: Include columnId for draft restoration
6706
7666
  value: fieldValue,
6707
7667
  period: {
@@ -6709,27 +7669,34 @@ let JupiterDynamicForm = class extends LitElement {
6709
7669
  }
6710
7670
  };
6711
7671
  if (concept.periodType === "instant") {
6712
- const instantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field.periodInstantDate || field.periodEndDate || field.periodStartDate || this.periodStartDate;
7672
+ const instantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodInstantDate || field2.periodEndDate || field2.periodStartDate || this.periodStartDate;
6713
7673
  submissionEntry.period.date = instantDate;
6714
7674
  } else {
6715
- const startDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field.periodStartDate || this.periodStartDate;
6716
- const endDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field.periodEndDate || this.periodEndDate;
7675
+ const startDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field2.periodStartDate || this.periodStartDate;
7676
+ const endDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodEndDate || this.periodEndDate;
6717
7677
  submissionEntry.period.startDate = startDate;
6718
7678
  submissionEntry.period.endDate = endDate;
6719
7679
  }
6720
- console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${field.columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}, Used Period: ${submissionEntry.period.type === "instant" ? submissionEntry.period.date : `${submissionEntry.period.startDate} - ${submissionEntry.period.endDate}`}`);
6721
- if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_b = column2.dimensionData) == null ? void 0 : _b.dimensionIdKey)) {
7680
+ console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${field2.columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}, Used Period: ${submissionEntry.period.type === "instant" ? submissionEntry.period.date : `${submissionEntry.period.startDate} - ${submissionEntry.period.endDate}`}`);
7681
+ const fieldUnit = (_b = this._unitData[concept.id]) == null ? void 0 : _b[field2.columnId];
7682
+ if (fieldUnit) {
7683
+ submissionEntry.unit = fieldUnit;
7684
+ console.log(`✅ [Submission] Adding unit to entry: ${fieldUnit} for ${concept.id}/${field2.columnId}`);
7685
+ } else {
7686
+ console.log(`⚠️ [Submission] No unit found in _unitData for ${concept.id}/${field2.columnId}. _unitData state:`, JSON.stringify(this._unitData, null, 2));
7687
+ }
7688
+ if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_c = column2.dimensionData) == null ? void 0 : _c.dimensionIdKey)) {
6722
7689
  submissionEntry.dimension = column2.dimensionData.dimensionIdKey;
6723
- console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field.columnId}):`, column2.dimensionData.dimensionIdKey);
7690
+ console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field2.columnId}):`, column2.dimensionData.dimensionIdKey);
6724
7691
  } else {
6725
- console.log(`🔍 [DynamicForm] No dimension data found for field column ${field.columnId}. Column type: ${column2 == null ? void 0 : column2.type}, has dimensionData: ${!!(column2 == null ? void 0 : column2.dimensionData)}`);
7692
+ console.log(`🔍 [DynamicForm] No dimension data found for field column ${field2.columnId}. Column type: ${column2 == null ? void 0 : column2.type}, has dimensionData: ${!!(column2 == null ? void 0 : column2.dimensionData)}`);
6726
7693
  }
6727
- if (this._typedMemberData[field.columnId]) {
7694
+ if (this._typedMemberData[field2.columnId]) {
6728
7695
  const applicableTypedDimensions = this._getApplicableTypedDimensions(concept, section2);
6729
7696
  console.log(`🔍 [DynamicForm] Concept ${concept.id} applicable typed dimensions:`, applicableTypedDimensions);
6730
7697
  if (applicableTypedDimensions.length > 0) {
6731
7698
  const filteredTypedMembers = {};
6732
- const allTypedMemberData = this._typedMemberData[field.columnId];
7699
+ const allTypedMemberData = this._typedMemberData[field2.columnId];
6733
7700
  applicableTypedDimensions.forEach((dimensionId) => {
6734
7701
  if (allTypedMemberData[dimensionId]) {
6735
7702
  const memberName = this._getTypedMemberNameForAxis(dimensionId, section2);
@@ -6749,12 +7716,12 @@ let JupiterDynamicForm = class extends LitElement {
6749
7716
  console.log(`🔍 [DynamicForm] Skipping typed members for concept ${concept.id} - not applicable to this hypercube`);
6750
7717
  }
6751
7718
  } else {
6752
- console.log(`🔍 [DynamicForm] No typed member data found for column ${field.columnId}. Available columns:`, Object.keys(this._typedMemberData));
7719
+ console.log(`🔍 [DynamicForm] No typed member data found for column ${field2.columnId}. Available columns:`, Object.keys(this._typedMemberData));
6753
7720
  if (column2) {
6754
7721
  console.log(`🔍 [DynamicForm] Column details:`, {
6755
7722
  id: column2.id,
6756
7723
  type: column2.type,
6757
- hasTypedMembers: (_c = column2.dimensionData) == null ? void 0 : _c.hasTypedMembers,
7724
+ hasTypedMembers: (_d = column2.dimensionData) == null ? void 0 : _d.hasTypedMembers,
6758
7725
  dimensionData: column2.dimensionData
6759
7726
  });
6760
7727
  }
@@ -6887,13 +7854,13 @@ let JupiterDynamicForm = class extends LitElement {
6887
7854
  </div>
6888
7855
  `;
6889
7856
  }
6890
- _handleAdminCheckboxChange(roleId, field, checked) {
7857
+ _handleAdminCheckboxChange(roleId, field2, checked) {
6891
7858
  const currentConfig = this._adminRoleConfigs[roleId] || { showPreviousYear: false };
6892
7859
  this._adminRoleConfigs = {
6893
7860
  ...this._adminRoleConfigs,
6894
7861
  [roleId]: {
6895
7862
  ...currentConfig,
6896
- [field]: checked
7863
+ [field2]: checked
6897
7864
  }
6898
7865
  };
6899
7866
  }
@@ -6943,8 +7910,8 @@ let JupiterDynamicForm = class extends LitElement {
6943
7910
  <div class="validation-summary">
6944
7911
  <h4 class="validation-summary-title">${I18n.t("validation.summary")}</h4>
6945
7912
  <ul class="validation-summary-list">
6946
- ${this._errors.filter((e2) => e2.severity === "error").map((error) => html`
6947
- <li class="validation-summary-item">${error.message}</li>
7913
+ ${this._errors.filter((e2) => e2.severity === "error").map((error2) => html`
7914
+ <li class="validation-summary-item">${error2.message}</li>
6948
7915
  `)}
6949
7916
  </ul>
6950
7917
  </div>
@@ -6961,12 +7928,19 @@ let JupiterDynamicForm = class extends LitElement {
6961
7928
  <p>${I18n.t("filter.selectRoles")}</p>
6962
7929
  <p>${I18n.t("filter.roles")}: ${this._allSections.length}</p>
6963
7930
  </div>
6964
- ` : schema.sections.map((section2, index) => html`
7931
+ ` : schema.sections.map((section2, index) => {
7932
+ var _a;
7933
+ return html`
6965
7934
  <jupiter-form-section
7935
+ section-id="${section2.id}"
6966
7936
  .section="${section2}"
6967
7937
  .columns="${section2.columns || this._columns}"
7938
+ .datatypes="${section2.datatypes || ((_a = this.xbrlInput) == null ? void 0 : _a.datatypes)}"
6968
7939
  .formData="${this._formData}"
7940
+ .periodData="${this._periodData}"
7941
+ .unitData="${this._unitData}"
6969
7942
  .typedMemberData="${this._typedMemberData}"
7943
+ .defaultUnits="${this.defaultUnits}"
6970
7944
  .disabled="${this.disabled || this.readonly}"
6971
7945
  .collapsible="${config.collapsibleSections !== false}"
6972
7946
  .locale="${config.locale || "en-US"}"
@@ -6980,11 +7954,13 @@ let JupiterDynamicForm = class extends LitElement {
6980
7954
  @column-remove="${this._handleColumnRemove}"
6981
7955
  @column-add-request="${this._handleColumnAddRequest}"
6982
7956
  ></jupiter-form-section>
6983
- `)}
7957
+ `;
7958
+ })}
6984
7959
  </div>
6985
7960
  `;
6986
7961
  }
6987
7962
  _renderSidePanelLayout(schema, config, showValidationSummary, errorCount) {
7963
+ var _a;
6988
7964
  const visibleSections = schema.sections;
6989
7965
  const filteredSections = this._filterSidePanelSections(visibleSections);
6990
7966
  if (!this._activeSidePanelRoleId || !filteredSections.find((s2) => s2.id === this._activeSidePanelRoleId)) {
@@ -7061,8 +8037,8 @@ let JupiterDynamicForm = class extends LitElement {
7061
8037
  <div class="validation-summary">
7062
8038
  <h4 class="validation-summary-title">Please fix the following errors:</h4>
7063
8039
  <ul class="validation-summary-list">
7064
- ${this._errors.filter((e2) => e2.severity === "error").map((error) => html`
7065
- <li class="validation-summary-item">${error.message}</li>
8040
+ ${this._errors.filter((e2) => e2.severity === "error").map((error2) => html`
8041
+ <li class="validation-summary-item">${error2.message}</li>
7066
8042
  `)}
7067
8043
  </ul>
7068
8044
  </div>
@@ -7075,10 +8051,15 @@ let JupiterDynamicForm = class extends LitElement {
7075
8051
  </div>
7076
8052
  ` : activeSection ? html`
7077
8053
  <jupiter-form-section
8054
+ section-id="${activeSection.id}"
7078
8055
  .section="${activeSection}"
7079
8056
  .columns="${activeSection.columns || this._columns}"
8057
+ .datatypes="${activeSection.datatypes || ((_a = this.xbrlInput) == null ? void 0 : _a.datatypes)}"
7080
8058
  .formData="${this._formData}"
8059
+ .periodData="${this._periodData}"
8060
+ .unitData="${this._unitData}"
7081
8061
  .typedMemberData="${this._typedMemberData}"
8062
+ .defaultUnits="${this.defaultUnits}"
7082
8063
  .disabled="${this.disabled || this.readonly}"
7083
8064
  .collapsible="${false}"
7084
8065
  .hideHeader="${true}"
@@ -7198,6 +8179,53 @@ let JupiterDynamicForm = class extends LitElement {
7198
8179
  @click="${this._handleFilterDialogCancel}"
7199
8180
  ></jupiter-filter-roles-dialog>
7200
8181
  ` : ""}
8182
+
8183
+ <!-- Validation Error Popup -->
8184
+ ${this._showErrorPopup ? html`
8185
+ <div class="error-popup-overlay" @click="${() => {
8186
+ this._showErrorPopup = false;
8187
+ this.requestUpdate();
8188
+ }}">
8189
+ <div class="error-popup" @click="${(e2) => e2.stopPropagation()}">
8190
+ <div class="error-popup-header">
8191
+ <h3>⚠️ ${I18n.t("error.popup.title")}</h3>
8192
+ <button class="error-popup-close" @click="${() => {
8193
+ this._showErrorPopup = false;
8194
+ this.requestUpdate();
8195
+ }}">×</button>
8196
+ </div>
8197
+ <div class="error-popup-content">
8198
+ <p>${I18n.t("error.popup.message")}</p>
8199
+ <ul class="error-list">
8200
+ ${this._xbrlFormErrors.map((error2) => html`
8201
+ <li>
8202
+ <strong>${I18n.t("error.popup.field")}</strong>
8203
+ <a
8204
+ href="javascript:void(0)"
8205
+ class="error-field-link"
8206
+ @click="${() => this._handleErrorFieldClick(error2.conceptId, error2.columnId, error2.sectionId)}"
8207
+ title="${I18n.t("error.popup.clickToFocus")}"
8208
+ >
8209
+ ${error2.conceptId}__${error2.columnId}
8210
+ </a><br>
8211
+ <strong>${I18n.t("error.popup.value")}</strong> ${error2.value}<br>
8212
+ <strong>${I18n.t("error.popup.errors")}</strong>
8213
+ <ul>
8214
+ ${error2.errors.map((err) => html`<li>${err.message}</li>`)}
8215
+ </ul>
8216
+ </li>
8217
+ `)}
8218
+ </ul>
8219
+ </div>
8220
+ <div class="error-popup-footer">
8221
+ <button class="btn-primary" @click="${() => {
8222
+ this._showErrorPopup = false;
8223
+ this.requestUpdate();
8224
+ }}">${I18n.t("error.popup.ok")}</button>
8225
+ </div>
8226
+ </div>
8227
+ </div>
8228
+ ` : ""}
7201
8229
  </div>
7202
8230
  `;
7203
8231
  }
@@ -7631,6 +8659,128 @@ JupiterDynamicForm.styles = css`
7631
8659
  cursor: pointer;
7632
8660
  user-select: none;
7633
8661
  }
8662
+
8663
+ /* Error Popup Styles */
8664
+ .error-popup-overlay {
8665
+ position: fixed;
8666
+ top: 0;
8667
+ left: 0;
8668
+ right: 0;
8669
+ bottom: 0;
8670
+ background: rgba(0, 0, 0, 0.5);
8671
+ display: flex;
8672
+ align-items: center;
8673
+ justify-content: center;
8674
+ z-index: 10000;
8675
+ }
8676
+
8677
+ .error-popup {
8678
+ background: white;
8679
+ border-radius: 8px;
8680
+ max-width: 600px;
8681
+ width: 90%;
8682
+ max-height: 80vh;
8683
+ overflow: hidden;
8684
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
8685
+ display: flex;
8686
+ flex-direction: column;
8687
+ }
8688
+
8689
+ .error-popup-header {
8690
+ display: flex;
8691
+ justify-content: space-between;
8692
+ align-items: center;
8693
+ padding: 20px 24px;
8694
+ border-bottom: 1px solid var(--jupiter-border-color, #ddd);
8695
+ background: var(--jupiter-section-header-background, #f0f2f5);
8696
+ }
8697
+
8698
+ .error-popup-header h3 {
8699
+ margin: 0;
8700
+ font-size: 18px;
8701
+ font-weight: 600;
8702
+ color: var(--jupiter-error-color, #d32f2f);
8703
+ }
8704
+
8705
+ .error-popup-close {
8706
+ background: transparent;
8707
+ border: none;
8708
+ font-size: 28px;
8709
+ cursor: pointer;
8710
+ padding: 0;
8711
+ width: 32px;
8712
+ height: 32px;
8713
+ display: flex;
8714
+ align-items: center;
8715
+ justify-content: center;
8716
+ border-radius: 4px;
8717
+ color: var(--jupiter-text-color, #333);
8718
+ transition: background-color 0.2s;
8719
+ }
8720
+
8721
+ .error-popup-close:hover {
8722
+ background-color: rgba(0, 0, 0, 0.05);
8723
+ }
8724
+
8725
+ .error-popup-content {
8726
+ padding: 24px;
8727
+ overflow-y: auto;
8728
+ flex: 1;
8729
+ }
8730
+
8731
+ .error-popup-content p {
8732
+ margin: 0 0 16px 0;
8733
+ color: var(--jupiter-text-primary, #333);
8734
+ }
8735
+
8736
+ .error-list {
8737
+ list-style: none;
8738
+ padding: 0;
8739
+ margin: 0;
8740
+ }
8741
+
8742
+ .error-list > li {
8743
+ padding: 12px;
8744
+ background: #f8f9fa;
8745
+ border: 1px solid #dee2e6;
8746
+ border-radius: 4px;
8747
+ margin-bottom: 12px;
8748
+ }
8749
+
8750
+ .error-list > li strong {
8751
+ color: var(--jupiter-text-primary, #333);
8752
+ font-weight: 600;
8753
+ }
8754
+
8755
+ .error-list ul {
8756
+ margin: 8px 0 0 0;
8757
+ padding-left: 20px;
8758
+ }
8759
+
8760
+ .error-list ul li {
8761
+ color: var(--jupiter-error-color, #d32f2f);
8762
+ margin: 4px 0;
8763
+ }
8764
+
8765
+ .error-popup-footer {
8766
+ padding: 16px 24px;
8767
+ border-top: 1px solid var(--jupiter-border-color, #ddd);
8768
+ display: flex;
8769
+ justify-content: flex-end;
8770
+ gap: 12px;
8771
+ }
8772
+
8773
+ .error-field-link {
8774
+ color: #0066cc;
8775
+ text-decoration: underline;
8776
+ cursor: pointer;
8777
+ font-family: monospace;
8778
+ }
8779
+
8780
+ .error-field-link:hover {
8781
+ color: #0052a3;
8782
+ text-decoration: none;
8783
+ }
7634
8784
  `;
7635
8785
  __decorateClass([
7636
8786
  n2({ type: Object })
@@ -7668,6 +8818,9 @@ __decorateClass([
7668
8818
  __decorateClass([
7669
8819
  n2({ type: Array })
7670
8820
  ], JupiterDynamicForm.prototype, "financialStatementsTypeAxis", 2);
8821
+ __decorateClass([
8822
+ n2({ type: Array })
8823
+ ], JupiterDynamicForm.prototype, "defaultUnits", 2);
7671
8824
  __decorateClass([
7672
8825
  n2({ type: Object, attribute: "dynaforms-metadata" })
7673
8826
  ], JupiterDynamicForm.prototype, "dynaformsMetadata", 2);
@@ -7692,6 +8845,12 @@ __decorateClass([
7692
8845
  __decorateClass([
7693
8846
  r()
7694
8847
  ], JupiterDynamicForm.prototype, "_preservedPeriodData", 2);
8848
+ __decorateClass([
8849
+ r()
8850
+ ], JupiterDynamicForm.prototype, "_unitData", 2);
8851
+ __decorateClass([
8852
+ r()
8853
+ ], JupiterDynamicForm.prototype, "_preservedUnitData", 2);
7695
8854
  __decorateClass([
7696
8855
  r()
7697
8856
  ], JupiterDynamicForm.prototype, "_typedMemberData", 2);
@@ -7716,6 +8875,12 @@ __decorateClass([
7716
8875
  __decorateClass([
7717
8876
  r()
7718
8877
  ], JupiterDynamicForm.prototype, "_submitted", 2);
8878
+ __decorateClass([
8879
+ r()
8880
+ ], JupiterDynamicForm.prototype, "_xbrlFormErrors", 2);
8881
+ __decorateClass([
8882
+ r()
8883
+ ], JupiterDynamicForm.prototype, "_showErrorPopup", 2);
7719
8884
  __decorateClass([
7720
8885
  r()
7721
8886
  ], JupiterDynamicForm.prototype, "_currentSchema", 2);
@@ -7756,11 +8921,15 @@ export {
7756
8921
  JupiterFormField,
7757
8922
  JupiterFormSection,
7758
8923
  TYPE_INPUT_MAP,
8924
+ XBRLValidator,
8925
+ collectEnumerationsFromChain,
8926
+ determineInputTypeFromBaseChain,
7759
8927
  getInputTypeForConceptType,
7760
8928
  isCheckboxType,
7761
8929
  isNumericType,
7762
8930
  isSelectType,
7763
8931
  isTextareaType,
8932
+ resolveBaseTypeChain,
7764
8933
  version
7765
8934
  };
7766
8935
  //# sourceMappingURL=index.mjs.map