jupiter-dynamic-forms 1.1.0 → 1.4.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
@@ -523,18 +523,33 @@ class FormValidator {
523
523
  }
524
524
  }
525
525
  class XBRLFormBuilder {
526
+ /**
527
+ * Create unique concept ID by combining original ID with preferred label suffix
528
+ * This handles cases where the same concept appears multiple times with different labels
529
+ */
530
+ static createUniqueConceptId(concept) {
531
+ if (concept.preferredLabel && concept.preferredLabel.trim() !== "") {
532
+ const roleMatch = concept.preferredLabel.match(/\/([^\/]+)$/);
533
+ const roleSuffix = roleMatch ? roleMatch[1] : concept.preferredLabel.replace(/[^a-zA-Z0-9]/g, "_");
534
+ return `${concept.id}_${roleSuffix}`;
535
+ }
536
+ return concept.id;
537
+ }
526
538
  /**
527
539
  * Build form schema from XBRL input data
528
540
  * Creates accordion sections for each presentation role
529
541
  */
530
542
  static buildFormSchema(xbrlInput, periodStartDate, periodEndDate) {
543
+ var _a;
531
544
  if (!xbrlInput.presentation || xbrlInput.presentation.length === 0) {
532
545
  throw new Error("XBRL presentation data is required");
533
546
  }
534
547
  const presentationData = xbrlInput.presentation[0];
548
+ const hypercubeData = (_a = xbrlInput.hypercubes) == null ? void 0 : _a[0];
535
549
  const sections = [];
536
550
  presentationData.roles.forEach((role) => {
537
- const section = this.buildSectionFromRole(role, periodStartDate, periodEndDate);
551
+ const section = this.buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData);
552
+ this.assignFieldColumnIds(section);
538
553
  sections.push(section);
539
554
  });
540
555
  return {
@@ -548,70 +563,116 @@ class XBRLFormBuilder {
548
563
  /**
549
564
  * Build a form section from a presentation role
550
565
  */
551
- static buildSectionFromRole(role, periodStartDate, periodEndDate) {
566
+ static buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData) {
552
567
  var _a;
553
568
  const title = this.extractRoleTitle(role.role);
569
+ const nonAbstractConcepts = this.getAllNonAbstractConcepts(role);
570
+ const periodTypes = new Set(
571
+ nonAbstractConcepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
572
+ );
573
+ const roleInfo = { periodTypes };
554
574
  const conceptTrees = [];
555
575
  if ((_a = role.presentationLinkbase) == null ? void 0 : _a.concepts) {
556
576
  role.presentationLinkbase.concepts.forEach((concept) => {
557
- const conceptTree = this.buildConceptTree(concept, 0, periodStartDate, periodEndDate);
577
+ const conceptTree = this.buildConceptTree(concept, 0, periodStartDate, periodEndDate, roleInfo);
558
578
  if (conceptTree) {
559
579
  conceptTrees.push(conceptTree);
560
580
  }
561
581
  });
562
582
  }
583
+ const hypercubeRole = hypercubeData == null ? void 0 : hypercubeData.roles.find((hr) => hr.roleId === role.id);
584
+ if (hypercubeRole) {
585
+ console.log(`🏷️ Found matching hypercube role "${role.id}"`);
586
+ } else {
587
+ console.log(`❌ No hypercube role found for "${role.id}"`);
588
+ }
589
+ const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31", hypercubeRole, nonAbstractConcepts, periodTypes);
563
590
  return {
564
591
  id: role.id,
565
592
  title,
566
593
  description: `Section for ${title}`,
567
594
  concepts: conceptTrees,
595
+ columns,
568
596
  expanded: false
569
597
  };
570
598
  }
571
599
  /**
572
600
  * Build concept tree from XBRL presentation concept
573
601
  */
574
- static buildConceptTree(concept, level, periodStartDate, periodEndDate) {
602
+ static buildConceptTree(concept, level, periodStartDate, periodEndDate, roleInfo) {
575
603
  const label = this.getPreferredLabel(concept.labels);
576
604
  const fields = [];
577
605
  if (!concept.elementAbstract) {
578
- const field = this.createFieldFromConcept(concept, periodStartDate, periodEndDate);
579
- if (field) {
580
- fields.push(field);
606
+ let shouldCreateField = true;
607
+ if ((roleInfo == null ? void 0 : roleInfo.periodTypes) && roleInfo.periodTypes.size > 1) {
608
+ if (concept.periodType === "instant") {
609
+ shouldCreateField = false;
610
+ }
611
+ }
612
+ if (shouldCreateField) {
613
+ let columnId;
614
+ if (!(roleInfo == null ? void 0 : roleInfo.periodTypes) || roleInfo.periodTypes.size === 0) {
615
+ columnId = "default";
616
+ } else if (roleInfo.periodTypes.size === 1 && roleInfo.periodTypes.has("instant")) {
617
+ columnId = "instant";
618
+ } else if (roleInfo.periodTypes.size === 1 && roleInfo.periodTypes.has("duration")) {
619
+ columnId = "duration";
620
+ } else {
621
+ columnId = "period";
622
+ }
623
+ const field = this.createFieldFromConcept(concept, periodStartDate, periodEndDate, columnId);
624
+ if (field)
625
+ fields.push(field);
581
626
  }
582
627
  }
583
628
  const children = [];
584
629
  if (concept.children && concept.children.length > 0) {
585
630
  concept.children.forEach((child) => {
586
- const childTree = this.buildConceptTree(child, level + 1, periodStartDate, periodEndDate);
631
+ const childTree = this.buildConceptTree(child, level + 1, periodStartDate, periodEndDate, roleInfo);
587
632
  if (childTree) {
588
633
  children.push(childTree);
589
634
  }
590
635
  });
591
636
  }
592
637
  return {
593
- id: concept.id,
638
+ id: this.createUniqueConceptId(concept),
639
+ // Use unique ID for form management
640
+ originalConceptId: concept.id,
641
+ // Store original for submission data
594
642
  name: concept.conceptName,
595
643
  label,
596
644
  description: `${concept.conceptName} (${concept.type})`,
597
645
  level,
598
646
  children,
599
647
  fields,
600
- collapsed: level > 0
648
+ collapsed: level > 0,
601
649
  // Collapse nested levels by default
650
+ abstract: concept.elementAbstract,
651
+ periodType: concept.periodType
602
652
  };
603
653
  }
604
654
  /**
605
655
  * Create form field from XBRL concept
606
656
  */
607
- static createFieldFromConcept(concept, periodStartDate, periodEndDate) {
657
+ static createFieldFromConcept(concept, periodStartDate, periodEndDate, forcedColumnId) {
608
658
  const fieldType = this.mapXBRLTypeToFieldType(concept.type);
609
659
  const label = this.getPreferredLabel(concept.labels);
660
+ let columnId;
661
+ if (forcedColumnId) {
662
+ columnId = forcedColumnId;
663
+ } else {
664
+ if (concept.periodType === "instant") {
665
+ columnId = "instant";
666
+ } else if (concept.periodType === "duration") {
667
+ columnId = "duration";
668
+ } else {
669
+ columnId = "default";
670
+ }
671
+ }
610
672
  const field = {
611
- id: `${concept.id}_field`,
673
+ id: `${concept.id}_${columnId}_field`,
612
674
  conceptId: concept.id,
613
- columnId: "default",
614
- // Default column, will be expanded later
675
+ columnId,
615
676
  type: fieldType,
616
677
  label,
617
678
  placeholder: `Enter ${label.toLowerCase()}`,
@@ -660,6 +721,238 @@ class XBRLFormBuilder {
660
721
  return terse.label;
661
722
  return labels[0].label;
662
723
  }
724
+ /**
725
+ * Assign appropriate column IDs to fields based on section's generated columns
726
+ */
727
+ static assignFieldColumnIds(section) {
728
+ if (!section.columns || section.columns.length === 0) {
729
+ return;
730
+ }
731
+ const columnIds = section.columns.map((col) => col.id);
732
+ section.concepts.forEach((conceptTree) => {
733
+ this.assignColumnIdsToConceptFields(conceptTree, columnIds);
734
+ });
735
+ }
736
+ /**
737
+ * Recursively assign column IDs to fields in a concept tree
738
+ */
739
+ static assignColumnIdsToConceptFields(conceptTree, columnIds) {
740
+ conceptTree.fields = conceptTree.fields.filter((field) => {
741
+ return columnIds.includes(field.columnId);
742
+ });
743
+ if (conceptTree.children) {
744
+ conceptTree.children.forEach((child) => {
745
+ this.assignColumnIdsToConceptFields(child, columnIds);
746
+ });
747
+ }
748
+ }
749
+ /**
750
+ * Count total fields in a concept tree recursively
751
+ */
752
+ static countFieldsInTree(conceptTree) {
753
+ let count = conceptTree.fields.length;
754
+ if (conceptTree.children) {
755
+ conceptTree.children.forEach((child) => {
756
+ count += this.countFieldsInTree(child);
757
+ });
758
+ }
759
+ return count;
760
+ }
761
+ /**
762
+ * Get all non-abstract concepts from a role recursively
763
+ */
764
+ static getAllNonAbstractConcepts(role) {
765
+ var _a;
766
+ const nonAbstractConcepts = [];
767
+ if ((_a = role.presentationLinkbase) == null ? void 0 : _a.concepts) {
768
+ role.presentationLinkbase.concepts.forEach((concept) => {
769
+ this.collectNonAbstractConcepts(concept, nonAbstractConcepts);
770
+ });
771
+ }
772
+ return nonAbstractConcepts;
773
+ }
774
+ /**
775
+ * Recursively collect non-abstract concepts from a concept tree
776
+ */
777
+ static collectNonAbstractConcepts(concept, collection) {
778
+ if (!concept.elementAbstract) {
779
+ collection.push(concept);
780
+ }
781
+ if (concept.children && concept.children.length > 0) {
782
+ concept.children.forEach((child) => {
783
+ this.collectNonAbstractConcepts(child, collection);
784
+ });
785
+ }
786
+ }
787
+ /**
788
+ * Generate default columns based on period types of non-abstract concepts in a role
789
+ */
790
+ static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate, hypercubeRole, nonAbstractConcepts, rolePeriodTypes) {
791
+ var _a, _b, _c, _d, _e;
792
+ const concepts = nonAbstractConcepts || this.getAllNonAbstractConcepts(role);
793
+ const periodTypes = rolePeriodTypes || new Set(
794
+ concepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
795
+ );
796
+ console.log(`📊 Analyzing role "${role.role}" with ${concepts.length} non-abstract concepts`);
797
+ if (concepts.length === 0) {
798
+ console.log("📊 No non-abstract concepts found, using default column");
799
+ return [{
800
+ id: "default",
801
+ title: "Value",
802
+ description: "Default value column",
803
+ type: "base",
804
+ order: 0,
805
+ removable: false
806
+ }];
807
+ }
808
+ let dimensionInfo = null;
809
+ if (((_a = hypercubeRole == null ? void 0 : hypercubeRole.items) == null ? void 0 : _a.length) === 1) {
810
+ const item = hypercubeRole.items[0];
811
+ console.log(`🔍 Processing hypercube item for role "${role.role}":`, {
812
+ itemId: item.id,
813
+ conceptIds: ((_b = item.conceptIds) == null ? void 0 : _b.length) || 0,
814
+ dimensions: item.dimensions.length
815
+ });
816
+ if (item.dimensions.length === 1) {
817
+ const dimension = item.dimensions[0];
818
+ console.log(`📊 Found single dimension:`, {
819
+ id: dimension.id,
820
+ conceptName: dimension.conceptName,
821
+ membersCount: dimension.members.length
822
+ });
823
+ if (dimension.members.length > 0) {
824
+ const axisLabel = ((_c = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _c.label) || dimension.conceptName;
825
+ const firstMember = dimension.members[0];
826
+ const memberLabel = ((_d = firstMember.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _d.label) || firstMember.conceptName;
827
+ dimensionInfo = {
828
+ axisId: dimension.id,
829
+ axisLabel,
830
+ memberId: firstMember.id,
831
+ memberLabel,
832
+ dimensionKey: `${axisLabel} | ${memberLabel}`,
833
+ dimensionIdKey: `${dimension.id} | ${firstMember.id}`
834
+ };
835
+ console.log(`📊 Generated dimension info:`, dimensionInfo);
836
+ }
837
+ } else {
838
+ console.log(`⚠️ Multiple dimensions found (${item.dimensions.length}), skipping for now`);
839
+ }
840
+ } else if (((_e = hypercubeRole == null ? void 0 : hypercubeRole.items) == null ? void 0 : _e.length) && hypercubeRole.items.length > 1) {
841
+ console.log(`⚠️ Multiple items found (${hypercubeRole.items.length}), skipping for now`);
842
+ }
843
+ console.log(`📅 Found period types: ${Array.from(periodTypes).join(", ")}`);
844
+ const columns = [];
845
+ if (periodTypes.size === 0) {
846
+ console.log("📅 No period types found, using default column");
847
+ const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel}` : "Value";
848
+ columns.push({
849
+ id: "default",
850
+ title: columnTitle,
851
+ description: "Default value column",
852
+ type: dimensionInfo ? "dimension" : "base",
853
+ dimensionData: dimensionInfo ? {
854
+ dimensionId: "default",
855
+ axisId: dimensionInfo.axisId,
856
+ memberId: dimensionInfo.memberId,
857
+ memberValue: dimensionInfo.memberLabel,
858
+ memberLabel: dimensionInfo.memberLabel,
859
+ axis: dimensionInfo.axisLabel,
860
+ axisLabel: dimensionInfo.axisLabel,
861
+ memberKey: dimensionInfo.dimensionKey,
862
+ dimensionIdKey: dimensionInfo.dimensionIdKey
863
+ } : void 0,
864
+ order: 0,
865
+ removable: false
866
+ });
867
+ } else if (periodTypes.size === 1 && periodTypes.has("instant")) {
868
+ console.log("📅 All concepts are instant type, creating single column");
869
+ const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)})` : `As of ${this.formatDateForDisplay(periodStartDate)}`;
870
+ columns.push({
871
+ id: "instant",
872
+ title: columnTitle,
873
+ description: `Values as of ${periodStartDate}`,
874
+ type: dimensionInfo ? "dimension" : "base",
875
+ dimensionData: dimensionInfo ? {
876
+ dimensionId: "instant",
877
+ axisId: dimensionInfo.axisId,
878
+ memberId: dimensionInfo.memberId,
879
+ memberValue: dimensionInfo.memberLabel,
880
+ memberLabel: dimensionInfo.memberLabel,
881
+ axis: dimensionInfo.axisLabel,
882
+ axisLabel: dimensionInfo.axisLabel,
883
+ memberKey: dimensionInfo.dimensionKey,
884
+ dimensionIdKey: dimensionInfo.dimensionIdKey
885
+ } : void 0,
886
+ order: 0,
887
+ removable: false
888
+ });
889
+ } else if (periodTypes.size === 1 && periodTypes.has("duration")) {
890
+ console.log("📅 All concepts are duration type, creating single column with period range");
891
+ const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})` : `${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)}`;
892
+ columns.push({
893
+ id: "duration",
894
+ title: columnTitle,
895
+ description: `Period: ${periodStartDate} to ${periodEndDate}`,
896
+ type: dimensionInfo ? "dimension" : "base",
897
+ dimensionData: dimensionInfo ? {
898
+ dimensionId: "duration",
899
+ axisId: dimensionInfo.axisId,
900
+ memberId: dimensionInfo.memberId,
901
+ memberValue: dimensionInfo.memberLabel,
902
+ memberLabel: dimensionInfo.memberLabel,
903
+ axis: dimensionInfo.axisLabel,
904
+ axisLabel: dimensionInfo.axisLabel,
905
+ memberKey: dimensionInfo.dimensionKey,
906
+ dimensionIdKey: dimensionInfo.dimensionIdKey
907
+ } : void 0,
908
+ order: 0,
909
+ removable: false
910
+ });
911
+ console.log("📅 Created duration column:", columns.map((c2) => ({ id: c2.id, title: c2.title })));
912
+ } else {
913
+ console.log("📅 Mixed period types found, creating single column with period range");
914
+ const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})` : `${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)}`;
915
+ columns.push({
916
+ id: "period",
917
+ title: columnTitle,
918
+ description: `Period: ${periodStartDate} to ${periodEndDate}`,
919
+ type: dimensionInfo ? "dimension" : "base",
920
+ dimensionData: dimensionInfo ? {
921
+ dimensionId: "period",
922
+ axisId: dimensionInfo.axisId,
923
+ memberId: dimensionInfo.memberId,
924
+ memberValue: dimensionInfo.memberLabel,
925
+ memberLabel: dimensionInfo.memberLabel,
926
+ axis: dimensionInfo.axisLabel,
927
+ axisLabel: dimensionInfo.axisLabel,
928
+ memberKey: dimensionInfo.dimensionKey,
929
+ dimensionIdKey: dimensionInfo.dimensionIdKey
930
+ } : void 0,
931
+ order: 0,
932
+ removable: false
933
+ });
934
+ }
935
+ if (dimensionInfo) {
936
+ console.log(`📊 Applied dimension to ${columns.length} columns: ${dimensionInfo.dimensionKey}`);
937
+ }
938
+ console.log(`📊 Generated ${columns.length} columns for role "${role.role}":`, columns.map((c2) => c2.title));
939
+ return columns;
940
+ }
941
+ /**
942
+ * Format date for display in column headers
943
+ */
944
+ static formatDateForDisplay(dateString) {
945
+ try {
946
+ const date = new Date(dateString);
947
+ return date.toLocaleDateString("en-US", {
948
+ year: "numeric",
949
+ month: "short",
950
+ day: "numeric"
951
+ });
952
+ } catch {
953
+ return dateString;
954
+ }
955
+ }
663
956
  /**
664
957
  * Extract entity name from entrypoint URL
665
958
  */
@@ -698,15 +991,15 @@ class XBRLFormBuilder {
698
991
  }];
699
992
  }
700
993
  }
701
- var __defProp$3 = Object.defineProperty;
702
- var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
703
- var __decorateClass$3 = (decorators, target, key, kind) => {
704
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
994
+ var __defProp$4 = Object.defineProperty;
995
+ var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
996
+ var __decorateClass$4 = (decorators, target, key, kind) => {
997
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
705
998
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
706
999
  if (decorator = decorators[i2])
707
1000
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
708
1001
  if (kind && result)
709
- __defProp$3(target, key, result);
1002
+ __defProp$4(target, key, result);
710
1003
  return result;
711
1004
  };
712
1005
  let JupiterFormField = class extends LitElement {
@@ -715,6 +1008,7 @@ let JupiterFormField = class extends LitElement {
715
1008
  this.value = null;
716
1009
  this.disabled = false;
717
1010
  this.locale = "en-US";
1011
+ this.hideLabel = false;
718
1012
  this._errors = [];
719
1013
  this._touched = false;
720
1014
  }
@@ -783,10 +1077,14 @@ let JupiterFormField = class extends LitElement {
783
1077
  const hasErrors = this._errors.some((e2) => e2.severity === "error");
784
1078
  const hasWarnings = this._errors.some((e2) => e2.severity === "warning");
785
1079
  const cssClass = `field-input ${hasErrors ? "error" : hasWarnings ? "warning" : ""}`;
1080
+ const fieldId = `${this.conceptId}__${this.columnId}`;
1081
+ const fieldName = `data[${this.conceptId}][${this.columnId}]`;
786
1082
  switch (this.field.type) {
787
1083
  case "textarea":
788
1084
  return html`
789
1085
  <textarea
1086
+ id="${fieldId}"
1087
+ name="${fieldName}"
790
1088
  class="${cssClass}"
791
1089
  .value="${this.value || ""}"
792
1090
  ?disabled="${this.disabled || this.field.disabled}"
@@ -799,6 +1097,8 @@ let JupiterFormField = class extends LitElement {
799
1097
  case "select":
800
1098
  return html`
801
1099
  <select
1100
+ id="${fieldId}"
1101
+ name="${fieldName}"
802
1102
  class="${cssClass}"
803
1103
  .value="${this.value || ""}"
804
1104
  ?disabled="${this.disabled || this.field.disabled}"
@@ -822,6 +1122,8 @@ let JupiterFormField = class extends LitElement {
822
1122
  return html`
823
1123
  <div class="checkbox-container">
824
1124
  <input
1125
+ id="${fieldId}"
1126
+ name="${fieldName}"
825
1127
  type="checkbox"
826
1128
  class="field-input"
827
1129
  .checked="${Boolean(this.value)}"
@@ -836,6 +1138,8 @@ let JupiterFormField = class extends LitElement {
836
1138
  default:
837
1139
  return html`
838
1140
  <input
1141
+ id="${fieldId}"
1142
+ name="${fieldName}"
839
1143
  type="${this._getInputType()}"
840
1144
  class="${cssClass}"
841
1145
  .value="${this.value || ""}"
@@ -870,7 +1174,7 @@ let JupiterFormField = class extends LitElement {
870
1174
  }
871
1175
  }
872
1176
  render() {
873
- const showLabel = this.field.type !== "boolean";
1177
+ const showLabel = !this.hideLabel && this.field.type !== "boolean";
874
1178
  return html`
875
1179
  <div class="field-container">
876
1180
  ${showLabel ? html`
@@ -897,7 +1201,11 @@ let JupiterFormField = class extends LitElement {
897
1201
  JupiterFormField.styles = css`
898
1202
  :host {
899
1203
  display: block;
900
- margin-bottom: 8px;
1204
+ margin-bottom: 0px; /* Remove bottom margin for table layout */
1205
+ }
1206
+
1207
+ :host([hideLabel]) {
1208
+ margin-bottom: 0px;
901
1209
  }
902
1210
 
903
1211
  .field-container {
@@ -919,10 +1227,10 @@ JupiterFormField.styles = css`
919
1227
 
920
1228
  .field-input {
921
1229
  width: 100%;
922
- padding: 8px 12px;
1230
+ padding: 6px 8px; /* Reduced padding for table cells */
923
1231
  border: 1px solid var(--jupiter-border-color, #ddd);
924
1232
  border-radius: 4px;
925
- font-size: 14px;
1233
+ font-size: 13px; /* Slightly smaller font for table */
926
1234
  font-family: inherit;
927
1235
  background: var(--jupiter-input-background, #fff);
928
1236
  color: var(--jupiter-text-primary, #333);
@@ -996,42 +1304,45 @@ JupiterFormField.styles = css`
996
1304
  width: auto;
997
1305
  }
998
1306
  `;
999
- __decorateClass$3([
1307
+ __decorateClass$4([
1000
1308
  n2({ type: Object })
1001
1309
  ], JupiterFormField.prototype, "field", 2);
1002
- __decorateClass$3([
1310
+ __decorateClass$4([
1003
1311
  n2({ type: String })
1004
1312
  ], JupiterFormField.prototype, "conceptId", 2);
1005
- __decorateClass$3([
1313
+ __decorateClass$4([
1006
1314
  n2({ type: String })
1007
1315
  ], JupiterFormField.prototype, "columnId", 2);
1008
- __decorateClass$3([
1316
+ __decorateClass$4([
1009
1317
  n2()
1010
1318
  ], JupiterFormField.prototype, "value", 2);
1011
- __decorateClass$3([
1319
+ __decorateClass$4([
1012
1320
  n2({ type: Boolean })
1013
1321
  ], JupiterFormField.prototype, "disabled", 2);
1014
- __decorateClass$3([
1322
+ __decorateClass$4([
1015
1323
  n2({ type: String })
1016
1324
  ], JupiterFormField.prototype, "locale", 2);
1017
- __decorateClass$3([
1325
+ __decorateClass$4([
1326
+ n2({ type: Boolean })
1327
+ ], JupiterFormField.prototype, "hideLabel", 2);
1328
+ __decorateClass$4([
1018
1329
  r()
1019
1330
  ], JupiterFormField.prototype, "_errors", 2);
1020
- __decorateClass$3([
1331
+ __decorateClass$4([
1021
1332
  r()
1022
1333
  ], JupiterFormField.prototype, "_touched", 2);
1023
- JupiterFormField = __decorateClass$3([
1334
+ JupiterFormField = __decorateClass$4([
1024
1335
  t$1("jupiter-form-field")
1025
1336
  ], JupiterFormField);
1026
- var __defProp$2 = Object.defineProperty;
1027
- var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
1028
- var __decorateClass$2 = (decorators, target, key, kind) => {
1029
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
1337
+ var __defProp$3 = Object.defineProperty;
1338
+ var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
1339
+ var __decorateClass$3 = (decorators, target, key, kind) => {
1340
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
1030
1341
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
1031
1342
  if (decorator = decorators[i2])
1032
1343
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
1033
1344
  if (kind && result)
1034
- __defProp$2(target, key, result);
1345
+ __defProp$3(target, key, result);
1035
1346
  return result;
1036
1347
  };
1037
1348
  let JupiterConceptTree = class extends LitElement {
@@ -1041,11 +1352,18 @@ let JupiterConceptTree = class extends LitElement {
1041
1352
  this.formData = {};
1042
1353
  this.disabled = false;
1043
1354
  this.locale = "en-US";
1355
+ this.expandedConcepts = /* @__PURE__ */ new Set();
1044
1356
  this._expanded = true;
1045
1357
  }
1046
1358
  connectedCallback() {
1047
1359
  super.connectedCallback();
1048
- this._expanded = !this.concept.collapsed;
1360
+ this._expanded = this.expandedConcepts.has(this.concept.id);
1361
+ }
1362
+ willUpdate(changedProperties) {
1363
+ super.willUpdate(changedProperties);
1364
+ if (changedProperties.has("expandedConcepts")) {
1365
+ this._expanded = this.expandedConcepts.has(this.concept.id);
1366
+ }
1049
1367
  }
1050
1368
  _toggleExpanded() {
1051
1369
  this._expanded = !this._expanded;
@@ -1058,7 +1376,8 @@ let JupiterConceptTree = class extends LitElement {
1058
1376
  }));
1059
1377
  }
1060
1378
  _getFieldForColumn(columnId) {
1061
- return this.concept.fields.find((field) => field.columnId === columnId);
1379
+ var _a;
1380
+ return (_a = this.concept.fields) == null ? void 0 : _a.find((field) => field.columnId === columnId);
1062
1381
  }
1063
1382
  _getFieldValue(field) {
1064
1383
  var _a;
@@ -1074,104 +1393,103 @@ let JupiterConceptTree = class extends LitElement {
1074
1393
  render() {
1075
1394
  const hasChildren = this.concept.children && this.concept.children.length > 0;
1076
1395
  const level = this.concept.level || 0;
1396
+ const isAbstract = this.concept.abstract || false;
1077
1397
  return html`
1078
- <div class="concept-row" style="--level: ${level}">
1079
- <!-- Concept Label Column -->
1080
- <div class="concept-header" @click="${this._toggleExpanded}">
1398
+ <!-- Concept Name Cell (Left Column) -->
1399
+ <td class="concept-name-cell ${isAbstract ? "abstract" : hasChildren ? "" : "leaf"}">
1400
+ <div class="concept-content" style="--level: ${level}">
1081
1401
  <div class="concept-indent"></div>
1082
- <div class="concept-toggle ${hasChildren ? this._expanded ? "expanded" : "" : "no-children"}">
1402
+ <div class="concept-toggle ${hasChildren ? this._expanded ? "expanded" : "" : "no-children"}"
1403
+ @click="${this._toggleExpanded}">
1083
1404
  ${hasChildren ? "▶" : ""}
1084
1405
  </div>
1085
- <div class="concept-label">
1406
+ <div class="concept-label"
1407
+ @click="${this._toggleExpanded}"
1408
+ title="${this.concept.id}${this.concept.description ? " - " + this.concept.description : ""}">
1086
1409
  ${this.concept.label}
1087
- ${this.concept.description ? html`
1088
- <span class="concept-description">${this.concept.description}</span>
1089
- ` : ""}
1090
1410
  </div>
1091
1411
  </div>
1412
+ </td>
1092
1413
 
1093
- <!-- Field Columns -->
1094
- ${this.columns.map((column) => {
1414
+ <!-- Input Field Cells (Period Columns) - Only for non-abstract concepts -->
1415
+ ${this.columns.map((column) => {
1095
1416
  const field = this._getFieldForColumn(column.id);
1417
+ const shouldShowField = !isAbstract && field;
1096
1418
  return html`
1097
- <div class="field-cell ${!field ? "empty" : ""}">
1098
- ${field ? html`
1099
- <jupiter-form-field
1100
- .field="${field}"
1101
- .conceptId="${this.concept.id}"
1102
- .columnId="${column.id}"
1103
- .value="${this._getFieldValue(field)}"
1104
- .disabled="${this.disabled}"
1105
- .locale="${this.locale}"
1106
- @field-change="${this._handleFieldChange}"
1107
- ></jupiter-form-field>
1108
- ` : ""}
1109
- </div>
1110
- `;
1419
+ <td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""}">
1420
+ ${shouldShowField ? html`
1421
+ <jupiter-form-field
1422
+ .field="${field}"
1423
+ .conceptId="${this.concept.id}"
1424
+ .columnId="${column.id}"
1425
+ .value="${this._getFieldValue(field)}"
1426
+ .disabled="${this.disabled}"
1427
+ .locale="${this.locale}"
1428
+ .hideLabel="${true}"
1429
+ @field-change="${this._handleFieldChange}"
1430
+ ></jupiter-form-field>
1431
+ ` : ""}
1432
+ </td>
1433
+ `;
1111
1434
  })}
1112
- </div>
1113
-
1114
- <!-- Children Concepts -->
1115
- ${hasChildren ? html`
1116
- <div class="children ${!this._expanded ? "collapsed" : ""}">
1117
- ${this.concept.children.map((child) => html`
1118
- <jupiter-concept-tree
1119
- .concept="${child}"
1120
- .columns="${this.columns}"
1121
- .formData="${this.formData}"
1122
- .disabled="${this.disabled}"
1123
- .locale="${this.locale}"
1124
- @field-change="${this._handleFieldChange}"
1125
- @concept-expand="${(e2) => {
1126
- e2.stopPropagation();
1127
- this.dispatchEvent(new CustomEvent("concept-expand", { detail: e2.detail, bubbles: true }));
1128
- }}"
1129
- ></jupiter-concept-tree>
1130
- `)}
1131
- </div>
1132
- ` : ""}
1133
1435
  `;
1134
1436
  }
1135
1437
  };
1136
1438
  JupiterConceptTree.styles = css`
1137
1439
  :host {
1138
- display: block;
1139
- }
1140
-
1141
- .concept-row {
1440
+ /* Component renders table cells directly */
1142
1441
  display: contents;
1143
1442
  }
1144
1443
 
1145
- .concept-header {
1146
- display: flex;
1147
- align-items: center;
1148
- padding: 8px 12px;
1149
- background: var(--jupiter-concept-background, #f8f9fa);
1444
+ .concept-name-cell {
1445
+ vertical-align: top;
1446
+ padding: 2px 4px;
1150
1447
  border: 1px solid var(--jupiter-border-color, #ddd);
1151
1448
  border-bottom: none;
1152
- font-weight: 500;
1153
- cursor: pointer;
1154
- user-select: none;
1449
+ background: var(--jupiter-concept-background, #f8f9fa);
1450
+ position: sticky;
1451
+ left: 0;
1452
+ z-index: 1;
1453
+ width: 300px;
1454
+ min-width: 300px;
1455
+ max-width: 300px;
1155
1456
  }
1156
1457
 
1157
- .concept-header:hover {
1158
- background: var(--jupiter-concept-hover-background, #e9ecef);
1458
+ .concept-name-cell.abstract {
1459
+ background: var(--jupiter-abstract-background, #f0f2f5);
1460
+ font-weight: 600;
1461
+ }
1462
+
1463
+ .concept-name-cell.leaf {
1464
+ background: var(--jupiter-leaf-background, #fff);
1465
+ font-weight: 400;
1466
+ }
1467
+
1468
+ .concept-content {
1469
+ display: flex;
1470
+ align-items: center;
1471
+ min-height: 28px;
1472
+ font-size: 13px;
1473
+ line-height: 1.3;
1474
+ width: 100%;
1475
+ overflow: hidden;
1159
1476
  }
1160
1477
 
1161
1478
  .concept-indent {
1162
- width: calc(var(--level, 0) * 20px);
1479
+ width: calc(var(--level, 0) * 16px);
1163
1480
  flex-shrink: 0;
1164
1481
  }
1165
1482
 
1166
1483
  .concept-toggle {
1167
- width: 16px;
1168
- height: 16px;
1169
- margin-right: 8px;
1484
+ width: 14px;
1485
+ height: 14px;
1486
+ margin-right: 6px;
1170
1487
  display: flex;
1171
1488
  align-items: center;
1172
1489
  justify-content: center;
1173
- font-size: 12px;
1490
+ font-size: 10px;
1174
1491
  transition: transform 0.2s ease;
1492
+ cursor: pointer;
1175
1493
  }
1176
1494
 
1177
1495
  .concept-toggle.expanded {
@@ -1185,71 +1503,390 @@ JupiterConceptTree.styles = css`
1185
1503
  .concept-label {
1186
1504
  flex: 1;
1187
1505
  color: var(--jupiter-text-primary, #333);
1188
- }
1189
-
1190
- .concept-description {
1191
- font-size: 12px;
1192
- color: var(--jupiter-text-secondary, #666);
1193
- font-weight: normal;
1194
- margin-left: 8px;
1195
- }
1196
-
1197
- .concept-fields {
1198
- display: contents;
1506
+ cursor: pointer;
1507
+ word-wrap: break-word;
1508
+ overflow-wrap: break-word;
1509
+ hyphens: auto;
1510
+ line-height: 1.3;
1511
+ min-width: 0; /* Allows flex item to shrink below content size */
1199
1512
  }
1200
1513
 
1201
1514
  .field-cell {
1515
+ vertical-align: middle;
1516
+ padding: 2px 6px;
1202
1517
  border: 1px solid var(--jupiter-border-color, #ddd);
1203
1518
  border-bottom: none;
1204
- padding: 8px;
1205
1519
  background: var(--jupiter-cell-background, #fff);
1206
- min-height: 40px;
1207
- display: flex;
1208
- align-items: center;
1209
- }
1210
-
1211
- .field-cell:last-child {
1212
- border-right: 1px solid var(--jupiter-border-color, #ddd);
1520
+ min-height: 28px;
1521
+ text-align: center;
1522
+ min-width: 180px;
1523
+ width: 180px;
1213
1524
  }
1214
1525
 
1215
1526
  .field-cell.empty {
1216
1527
  background: var(--jupiter-empty-cell-background, #f8f9fa);
1217
1528
  }
1218
1529
 
1219
- .children {
1220
- display: contents;
1530
+ .field-cell.abstract-row {
1531
+ background: var(--jupiter-abstract-cell-background, #f0f2f5);
1221
1532
  }
1222
1533
 
1223
- .children.collapsed {
1534
+ /* Children are rendered as separate table rows, not nested */
1535
+ .children-wrapper {
1224
1536
  display: none;
1225
1537
  }
1226
-
1227
- .concept-row:last-of-type .concept-header,
1228
- .concept-row:last-of-type .field-cell {
1229
- border-bottom: 1px solid var(--jupiter-border-color, #ddd);
1230
- }
1231
1538
  `;
1232
- __decorateClass$2([
1539
+ __decorateClass$3([
1233
1540
  n2({ type: Object })
1234
1541
  ], JupiterConceptTree.prototype, "concept", 2);
1235
- __decorateClass$2([
1542
+ __decorateClass$3([
1236
1543
  n2({ type: Array })
1237
1544
  ], JupiterConceptTree.prototype, "columns", 2);
1238
- __decorateClass$2([
1545
+ __decorateClass$3([
1239
1546
  n2({ type: Object })
1240
1547
  ], JupiterConceptTree.prototype, "formData", 2);
1241
- __decorateClass$2([
1548
+ __decorateClass$3([
1242
1549
  n2({ type: Boolean })
1243
1550
  ], JupiterConceptTree.prototype, "disabled", 2);
1244
- __decorateClass$2([
1551
+ __decorateClass$3([
1245
1552
  n2({ type: String })
1246
1553
  ], JupiterConceptTree.prototype, "locale", 2);
1247
- __decorateClass$2([
1554
+ __decorateClass$3([
1555
+ n2({ type: Set })
1556
+ ], JupiterConceptTree.prototype, "expandedConcepts", 2);
1557
+ __decorateClass$3([
1248
1558
  r()
1249
1559
  ], JupiterConceptTree.prototype, "_expanded", 2);
1250
- JupiterConceptTree = __decorateClass$2([
1560
+ JupiterConceptTree = __decorateClass$3([
1251
1561
  t$1("jupiter-concept-tree")
1252
1562
  ], JupiterConceptTree);
1563
+ var __defProp$2 = Object.defineProperty;
1564
+ var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
1565
+ var __decorateClass$2 = (decorators, target, key, kind) => {
1566
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
1567
+ for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
1568
+ if (decorator = decorators[i2])
1569
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
1570
+ if (kind && result)
1571
+ __defProp$2(target, key, result);
1572
+ return result;
1573
+ };
1574
+ let JupiterAddColumnDialog = class extends LitElement {
1575
+ constructor() {
1576
+ super(...arguments);
1577
+ this.periodType = "duration";
1578
+ this.open = false;
1579
+ this._startDate = "";
1580
+ this._endDate = "";
1581
+ this._instantDate = "";
1582
+ this._selectedType = "duration";
1583
+ }
1584
+ updated(changedProperties) {
1585
+ if (changedProperties.has("open") && this.open) {
1586
+ this._resetForm();
1587
+ }
1588
+ }
1589
+ connectedCallback() {
1590
+ super.connectedCallback();
1591
+ this._resetForm();
1592
+ }
1593
+ willUpdate(changedProperties) {
1594
+ super.willUpdate(changedProperties);
1595
+ if (changedProperties.has("open") && this.open) {
1596
+ this._resetForm();
1597
+ }
1598
+ }
1599
+ _resetForm() {
1600
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1601
+ this._startDate = today;
1602
+ this._endDate = today;
1603
+ this._instantDate = today;
1604
+ this._selectedType = "duration";
1605
+ }
1606
+ _handleCancel() {
1607
+ this.open = false;
1608
+ this.dispatchEvent(new CustomEvent("dialog-cancel", { bubbles: true }));
1609
+ }
1610
+ _handleConfirm() {
1611
+ if (!this._isFormValid())
1612
+ return;
1613
+ const request = {
1614
+ periodType: this.periodType === "mixed" ? this._selectedType : this.periodType
1615
+ };
1616
+ if (this.periodType === "instant" || this.periodType === "mixed" && this._selectedType === "instant") {
1617
+ request.instantDate = this._instantDate;
1618
+ } else {
1619
+ request.startDate = this._startDate;
1620
+ request.endDate = this._endDate;
1621
+ }
1622
+ this.dispatchEvent(new CustomEvent("column-add", {
1623
+ detail: request,
1624
+ bubbles: true
1625
+ }));
1626
+ }
1627
+ _isFormValid() {
1628
+ if (this.periodType === "mixed") {
1629
+ if (this._selectedType === "instant") {
1630
+ return !!this._instantDate;
1631
+ } else {
1632
+ return !!this._startDate && !!this._endDate && this._startDate <= this._endDate;
1633
+ }
1634
+ } else if (this.periodType === "duration") {
1635
+ return !!this._startDate && !!this._endDate && this._startDate <= this._endDate;
1636
+ } else if (this.periodType === "instant") {
1637
+ return !!this._instantDate;
1638
+ }
1639
+ return false;
1640
+ }
1641
+ _handleStartDateChange(e2) {
1642
+ this._startDate = e2.target.value;
1643
+ }
1644
+ _handleEndDateChange(e2) {
1645
+ this._endDate = e2.target.value;
1646
+ }
1647
+ _handleSelectedTypeChange(e2) {
1648
+ this._selectedType = e2.target.value;
1649
+ }
1650
+ _handleInstantDateChange(e2) {
1651
+ this._instantDate = e2.target.value;
1652
+ }
1653
+ render() {
1654
+ if (!this.open)
1655
+ return html``;
1656
+ const isValid = this._isFormValid();
1657
+ return html`
1658
+ <div class="dialog" @click="${(e2) => e2.stopPropagation()}">
1659
+ <div class="dialog-header">
1660
+ <h2 class="dialog-title">Add Column</h2>
1661
+ <p class="dialog-description">
1662
+ ${this.periodType === "instant" ? "Add a new instant period column by specifying the date." : this.periodType === "duration" ? "Add a new duration period column by specifying the start and end dates." : "This section contains both instant and duration concepts. Choose the type of column to add."}
1663
+ </p>
1664
+ </div>
1665
+
1666
+ <div class="dialog-content">
1667
+ ${this.periodType === "mixed" ? html`
1668
+ <div class="form-group">
1669
+ <label class="form-label required">Column Type</label>
1670
+ <select
1671
+ class="form-input"
1672
+ .value="${this._selectedType}"
1673
+ @change="${this._handleSelectedTypeChange}"
1674
+ required
1675
+ >
1676
+ <option value="instant">Instant (single date)</option>
1677
+ <option value="duration">Duration (start and end dates)</option>
1678
+ </select>
1679
+ </div>
1680
+ ` : ""}
1681
+
1682
+ ${this.periodType === "instant" || this.periodType === "mixed" && this._selectedType === "instant" ? html`
1683
+ <div class="form-group">
1684
+ <label class="form-label required">Instant Date</label>
1685
+ <input
1686
+ type="date"
1687
+ class="form-input"
1688
+ .value="${this._instantDate}"
1689
+ @change="${this._handleInstantDateChange}"
1690
+ required
1691
+ />
1692
+ </div>
1693
+ ` : html`
1694
+ <div class="form-group">
1695
+ <label class="form-label required">Start Period Date</label>
1696
+ <input
1697
+ type="date"
1698
+ class="form-input"
1699
+ .value="${this._startDate}"
1700
+ @change="${this._handleStartDateChange}"
1701
+ required
1702
+ />
1703
+ </div>
1704
+ <div class="form-group">
1705
+ <label class="form-label required">End Period Date</label>
1706
+ <input
1707
+ type="date"
1708
+ class="form-input"
1709
+ .value="${this._endDate}"
1710
+ @change="${this._handleEndDateChange}"
1711
+ required
1712
+ />
1713
+ </div>
1714
+ `}
1715
+ </div>
1716
+
1717
+ <div class="dialog-actions">
1718
+ <button class="btn btn-cancel" @click="${this._handleCancel}">
1719
+ Cancel
1720
+ </button>
1721
+ <button
1722
+ class="btn btn-primary"
1723
+ ?disabled="${!isValid}"
1724
+ @click="${this._handleConfirm}"
1725
+ >
1726
+ Add Column
1727
+ </button>
1728
+ </div>
1729
+ </div>
1730
+ `;
1731
+ }
1732
+ };
1733
+ JupiterAddColumnDialog.styles = css`
1734
+ :host {
1735
+ position: fixed;
1736
+ top: 0;
1737
+ left: 0;
1738
+ width: 100%;
1739
+ height: 100%;
1740
+ background: rgba(0, 0, 0, 0.5);
1741
+ z-index: 1000;
1742
+ display: flex;
1743
+ align-items: center;
1744
+ justify-content: center;
1745
+ opacity: 0;
1746
+ visibility: hidden;
1747
+ transition: opacity 0.3s ease, visibility 0.3s ease;
1748
+ }
1749
+
1750
+ :host([open]) {
1751
+ opacity: 1;
1752
+ visibility: visible;
1753
+ }
1754
+
1755
+ .dialog {
1756
+ background: white;
1757
+ border-radius: 8px;
1758
+ padding: 24px;
1759
+ min-width: 400px;
1760
+ max-width: 500px;
1761
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
1762
+ transform: scale(0.9);
1763
+ transition: transform 0.3s ease;
1764
+ }
1765
+
1766
+ :host([open]) .dialog {
1767
+ transform: scale(1);
1768
+ }
1769
+
1770
+ .dialog-header {
1771
+ margin-bottom: 20px;
1772
+ }
1773
+
1774
+ .dialog-title {
1775
+ font-size: 20px;
1776
+ font-weight: 600;
1777
+ color: var(--jupiter-text-primary, #333);
1778
+ margin: 0 0 8px 0;
1779
+ }
1780
+
1781
+ .dialog-description {
1782
+ font-size: 14px;
1783
+ color: var(--jupiter-text-secondary, #666);
1784
+ margin: 0;
1785
+ }
1786
+
1787
+ .dialog-content {
1788
+ margin-bottom: 24px;
1789
+ }
1790
+
1791
+ .form-group {
1792
+ margin-bottom: 16px;
1793
+ }
1794
+
1795
+ .form-label {
1796
+ display: block;
1797
+ font-weight: 500;
1798
+ margin-bottom: 6px;
1799
+ color: var(--jupiter-text-primary, #333);
1800
+ font-size: 14px;
1801
+ }
1802
+
1803
+ .form-label.required::after {
1804
+ content: ' *';
1805
+ color: var(--jupiter-error-color, #d32f2f);
1806
+ }
1807
+
1808
+ .form-input {
1809
+ width: 100%;
1810
+ box-sizing: border-box;
1811
+ padding: 10px 12px;
1812
+ border: 1px solid var(--jupiter-border-color, #ddd);
1813
+ border-radius: 4px;
1814
+ font-size: 14px;
1815
+ font-family: inherit;
1816
+ transition: border-color 0.2s ease;
1817
+ }
1818
+
1819
+ .form-input:focus {
1820
+ outline: none;
1821
+ border-color: var(--jupiter-primary-color, #007bff);
1822
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
1823
+ }
1824
+
1825
+ select.form-input {
1826
+ cursor: pointer;
1827
+ background-color: white;
1828
+ }
1829
+
1830
+ .dialog-actions {
1831
+ display: flex;
1832
+ gap: 12px;
1833
+ justify-content: flex-end;
1834
+ }
1835
+
1836
+ .btn {
1837
+ padding: 10px 20px;
1838
+ border: none;
1839
+ border-radius: 4px;
1840
+ font-size: 14px;
1841
+ font-weight: 500;
1842
+ cursor: pointer;
1843
+ transition: background-color 0.2s ease;
1844
+ }
1845
+
1846
+ .btn-cancel {
1847
+ background: var(--jupiter-neutral-background, #f5f5f5);
1848
+ color: var(--jupiter-text-primary, #333);
1849
+ }
1850
+
1851
+ .btn-cancel:hover {
1852
+ background: var(--jupiter-neutral-background-hover, #e0e0e0);
1853
+ }
1854
+
1855
+ .btn-primary {
1856
+ background: var(--jupiter-primary-color, #667eea);
1857
+ color: white;
1858
+ }
1859
+
1860
+ .btn-primary:hover {
1861
+ background: var(--jupiter-primary-color-dark, #5a6fd8);
1862
+ }
1863
+
1864
+ .btn-primary:disabled {
1865
+ background: var(--jupiter-disabled-background, #ccc);
1866
+ cursor: not-allowed;
1867
+ }
1868
+ `;
1869
+ __decorateClass$2([
1870
+ n2({ type: String })
1871
+ ], JupiterAddColumnDialog.prototype, "periodType", 2);
1872
+ __decorateClass$2([
1873
+ n2({ type: Boolean })
1874
+ ], JupiterAddColumnDialog.prototype, "open", 2);
1875
+ __decorateClass$2([
1876
+ r()
1877
+ ], JupiterAddColumnDialog.prototype, "_startDate", 2);
1878
+ __decorateClass$2([
1879
+ r()
1880
+ ], JupiterAddColumnDialog.prototype, "_endDate", 2);
1881
+ __decorateClass$2([
1882
+ r()
1883
+ ], JupiterAddColumnDialog.prototype, "_instantDate", 2);
1884
+ __decorateClass$2([
1885
+ r()
1886
+ ], JupiterAddColumnDialog.prototype, "_selectedType", 2);
1887
+ JupiterAddColumnDialog = __decorateClass$2([
1888
+ t$1("jupiter-add-column-dialog")
1889
+ ], JupiterAddColumnDialog);
1253
1890
  var __defProp$1 = Object.defineProperty;
1254
1891
  var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
1255
1892
  var __decorateClass$1 = (decorators, target, key, kind) => {
@@ -1270,10 +1907,58 @@ let JupiterFormSection = class extends LitElement {
1270
1907
  this.collapsible = true;
1271
1908
  this.locale = "en-US";
1272
1909
  this._expanded = true;
1910
+ this._showAddColumnDialog = false;
1911
+ this._sectionPeriodType = "duration";
1912
+ this._expandedConcepts = /* @__PURE__ */ new Set();
1273
1913
  }
1274
1914
  connectedCallback() {
1275
1915
  super.connectedCallback();
1276
1916
  this._expanded = this.section.expanded !== false;
1917
+ this._determinePeriodType();
1918
+ }
1919
+ _determinePeriodType() {
1920
+ const nonAbstractConcepts = this._getAllNonAbstractConcepts(this.section.concepts);
1921
+ console.log(`🔍 Section ${this.section.id} (${this.section.title}): Found ${nonAbstractConcepts.length} non-abstract concepts`);
1922
+ console.log(`📝 All concepts in section:`, this.section.concepts.map((c2) => ({
1923
+ name: c2.name,
1924
+ abstract: c2.abstract,
1925
+ periodType: c2.periodType
1926
+ })));
1927
+ if (nonAbstractConcepts.length === 0) {
1928
+ this._sectionPeriodType = "duration";
1929
+ console.log(`📊 Section ${this.section.id}: No concepts, defaulting to duration`);
1930
+ return;
1931
+ }
1932
+ const periodTypes = new Set(nonAbstractConcepts.map((c2) => c2.periodType).filter(Boolean));
1933
+ console.log(`🏷️ Section ${this.section.id}: Found period types:`, Array.from(periodTypes));
1934
+ console.log(
1935
+ `📝 Section ${this.section.id}: Non-abstract concepts and their period types:`,
1936
+ nonAbstractConcepts.map((c2) => ({ name: c2.name, periodType: c2.periodType, abstract: c2.abstract }))
1937
+ );
1938
+ if (periodTypes.size === 0) {
1939
+ this._sectionPeriodType = "duration";
1940
+ console.log(`📊 Section ${this.section.id}: No period types defined, defaulting to duration`);
1941
+ } else if (periodTypes.size === 1) {
1942
+ const singleType = Array.from(periodTypes)[0];
1943
+ this._sectionPeriodType = singleType === "instant" ? "instant" : "duration";
1944
+ console.log(`📊 Section ${this.section.id}: Single period type '${singleType}', setting to '${this._sectionPeriodType}'`);
1945
+ } else {
1946
+ this._sectionPeriodType = "mixed";
1947
+ console.log(`📊 Section ${this.section.id}: Mixed period types, setting to 'mixed'`);
1948
+ }
1949
+ console.log(`✅ Section ${this.section.id}: Final period type: ${this._sectionPeriodType}`);
1950
+ }
1951
+ _getAllNonAbstractConcepts(concepts) {
1952
+ const result = [];
1953
+ for (const concept of concepts) {
1954
+ if (!concept.abstract) {
1955
+ result.push(concept);
1956
+ }
1957
+ if (concept.children) {
1958
+ result.push(...this._getAllNonAbstractConcepts(concept.children));
1959
+ }
1960
+ }
1961
+ return result;
1277
1962
  }
1278
1963
  _toggleExpanded() {
1279
1964
  if (!this.collapsible)
@@ -1289,7 +1974,58 @@ let JupiterFormSection = class extends LitElement {
1289
1974
  }
1290
1975
  _handleRemoveColumn(columnId) {
1291
1976
  this.dispatchEvent(new CustomEvent("column-remove", {
1292
- detail: { columnId },
1977
+ detail: {
1978
+ columnId,
1979
+ sectionId: this.section.id
1980
+ },
1981
+ bubbles: true
1982
+ }));
1983
+ }
1984
+ _handleAddColumn() {
1985
+ const buttonPeriodType = this._determineButtonPeriodType();
1986
+ this._sectionPeriodType = buttonPeriodType;
1987
+ this._showAddColumnDialog = true;
1988
+ }
1989
+ _determineButtonPeriodType() {
1990
+ const allNonAbstractConcepts = this._getAllNonAbstractConcepts(this.section.concepts);
1991
+ if (allNonAbstractConcepts.length === 0) {
1992
+ return "duration";
1993
+ }
1994
+ const periodTypes = new Set(
1995
+ allNonAbstractConcepts.map((c2) => c2.periodType).filter((periodType) => periodType !== void 0 && periodType !== null)
1996
+ );
1997
+ if (periodTypes.size === 0) {
1998
+ return "duration";
1999
+ } else if (periodTypes.size === 1) {
2000
+ const singleType = Array.from(periodTypes)[0];
2001
+ return singleType === "instant" ? "instant" : "duration";
2002
+ } else {
2003
+ return "mixed";
2004
+ }
2005
+ }
2006
+ _getConceptsWithFields(concepts) {
2007
+ const result = [];
2008
+ for (const concept of concepts) {
2009
+ if (!concept.abstract && concept.fields && concept.fields.length > 0) {
2010
+ result.push(concept);
2011
+ }
2012
+ if (concept.children) {
2013
+ result.push(...this._getConceptsWithFields(concept.children));
2014
+ }
2015
+ }
2016
+ return result;
2017
+ }
2018
+ _handleDialogCancel() {
2019
+ this._showAddColumnDialog = false;
2020
+ }
2021
+ _handleColumnAdd(event) {
2022
+ event.stopPropagation();
2023
+ this._showAddColumnDialog = false;
2024
+ this.dispatchEvent(new CustomEvent("column-add-request", {
2025
+ detail: {
2026
+ sectionId: this.section.id,
2027
+ columnRequest: event.detail
2028
+ },
1293
2029
  bubbles: true
1294
2030
  }));
1295
2031
  }
@@ -1300,8 +2036,26 @@ let JupiterFormSection = class extends LitElement {
1300
2036
  bubbles: true
1301
2037
  }));
1302
2038
  }
2039
+ _flattenConcepts(concepts, expanded = /* @__PURE__ */ new Set()) {
2040
+ const result = [];
2041
+ for (const concept of concepts) {
2042
+ result.push(concept);
2043
+ if (concept.children && concept.children.length > 0 && expanded.has(concept.id)) {
2044
+ const childrenFlattened = this._flattenConcepts(concept.children, expanded);
2045
+ result.push(...childrenFlattened);
2046
+ }
2047
+ }
2048
+ return result;
2049
+ }
1303
2050
  _handleConceptExpand(event) {
1304
2051
  event.stopPropagation();
2052
+ const { conceptId, expanded } = event.detail;
2053
+ if (expanded) {
2054
+ this._expandedConcepts.add(conceptId);
2055
+ } else {
2056
+ this._expandedConcepts.delete(conceptId);
2057
+ }
2058
+ this.requestUpdate();
1305
2059
  this.dispatchEvent(new CustomEvent("concept-expand", {
1306
2060
  detail: event.detail,
1307
2061
  bubbles: true
@@ -1348,7 +2102,7 @@ let JupiterFormSection = class extends LitElement {
1348
2102
  <div class="table-container">
1349
2103
  <table class="form-table">
1350
2104
  <thead class="table-header">
1351
- <tr>
2105
+ <tr class="header-row">
1352
2106
  <th class="header-cell concept-column">Concept</th>
1353
2107
  ${this.columns.map((column) => html`
1354
2108
  <th class="header-cell ${column.removable ? "removable" : ""}">
@@ -1366,24 +2120,43 @@ let JupiterFormSection = class extends LitElement {
1366
2120
  ` : ""}
1367
2121
  </th>
1368
2122
  `)}
2123
+ <th class="header-cell">
2124
+ <button class="add-column-btn" @click="${(e2) => {
2125
+ e2.stopPropagation();
2126
+ this._handleAddColumn();
2127
+ }}" title="Add Column">
2128
+ + Add Column
2129
+ </button>
2130
+ </th>
1369
2131
  </tr>
1370
2132
  </thead>
1371
2133
  <tbody class="table-body">
1372
- ${this.section.concepts.map((concept) => html`
1373
- <jupiter-concept-tree
1374
- .concept="${concept}"
1375
- .columns="${this.columns}"
1376
- .formData="${this.formData}"
1377
- .disabled="${this.disabled}"
1378
- .locale="${this.locale}"
1379
- @field-change="${this._handleFieldChange}"
1380
- @concept-expand="${this._handleConceptExpand}"
1381
- ></jupiter-concept-tree>
2134
+ ${this._flattenConcepts(this.section.concepts, this._expandedConcepts).map((concept) => html`
2135
+ <tr>
2136
+ <jupiter-concept-tree
2137
+ .concept="${concept}"
2138
+ .columns="${this.columns}"
2139
+ .formData="${this.formData}"
2140
+ .disabled="${this.disabled}"
2141
+ .locale="${this.locale}"
2142
+ .expandedConcepts="${this._expandedConcepts}"
2143
+ @field-change="${this._handleFieldChange}"
2144
+ @concept-expand="${this._handleConceptExpand}"
2145
+ ></jupiter-concept-tree>
2146
+ </tr>
1382
2147
  `)}
1383
2148
  </tbody>
1384
2149
  </table>
1385
2150
  </div>
1386
2151
  </div>
2152
+
2153
+ <!-- Add Column Dialog -->
2154
+ <jupiter-add-column-dialog
2155
+ .periodType="${this._sectionPeriodType}"
2156
+ ?open="${this._showAddColumnDialog}"
2157
+ @dialog-cancel="${this._handleDialogCancel}"
2158
+ @column-add="${this._handleColumnAdd}"
2159
+ ></jupiter-add-column-dialog>
1387
2160
  `;
1388
2161
  }
1389
2162
  };
@@ -1467,7 +2240,8 @@ JupiterFormSection.styles = css`
1467
2240
 
1468
2241
  .form-table {
1469
2242
  width: 100%;
1470
- border-collapse: collapse;
2243
+ border-collapse: separate;
2244
+ border-spacing: 0;
1471
2245
  background: var(--jupiter-table-background, #fff);
1472
2246
  }
1473
2247
 
@@ -1478,18 +2252,27 @@ JupiterFormSection.styles = css`
1478
2252
  z-index: 1;
1479
2253
  }
1480
2254
 
2255
+ .header-row {
2256
+ /* Table row - no special display needed */
2257
+ }
2258
+
1481
2259
  .header-cell {
1482
- padding: 12px;
2260
+ padding: 8px 12px;
1483
2261
  text-align: left;
1484
2262
  font-weight: 600;
1485
2263
  color: var(--jupiter-text-primary, #333);
1486
2264
  border: 1px solid var(--jupiter-border-color, #ddd);
1487
2265
  background: var(--jupiter-header-background, #f8f9fa);
1488
- min-width: 150px;
2266
+ min-width: 180px;
2267
+ width: 180px;
2268
+ font-size: 14px;
2269
+ vertical-align: middle;
1489
2270
  }
1490
2271
 
1491
2272
  .header-cell.concept-column {
2273
+ width: 300px;
1492
2274
  min-width: 300px;
2275
+ max-width: 300px;
1493
2276
  position: sticky;
1494
2277
  left: 0;
1495
2278
  z-index: 2;
@@ -1520,8 +2303,19 @@ JupiterFormSection.styles = css`
1520
2303
  background: var(--jupiter-error-color-dark, #b71c1c);
1521
2304
  }
1522
2305
 
1523
- .table-body {
1524
- display: table-row-group;
2306
+ .add-column-btn {
2307
+ background: var(--jupiter-primary-color, #667eea);
2308
+ color: white;
2309
+ border: none;
2310
+ padding: 8px 16px;
2311
+ border-radius: 4px;
2312
+ cursor: pointer;
2313
+ font-size: 12px;
2314
+ margin: 8px;
2315
+ }
2316
+
2317
+ .add-column-btn:hover {
2318
+ background: var(--jupiter-primary-color-dark, #5a6fd8);
1525
2319
  }
1526
2320
 
1527
2321
  .empty-section {
@@ -1552,6 +2346,15 @@ __decorateClass$1([
1552
2346
  __decorateClass$1([
1553
2347
  r()
1554
2348
  ], JupiterFormSection.prototype, "_expanded", 2);
2349
+ __decorateClass$1([
2350
+ r()
2351
+ ], JupiterFormSection.prototype, "_showAddColumnDialog", 2);
2352
+ __decorateClass$1([
2353
+ r()
2354
+ ], JupiterFormSection.prototype, "_sectionPeriodType", 2);
2355
+ __decorateClass$1([
2356
+ r()
2357
+ ], JupiterFormSection.prototype, "_expandedConcepts", 2);
1555
2358
  JupiterFormSection = __decorateClass$1([
1556
2359
  t$1("jupiter-form-section")
1557
2360
  ], JupiterFormSection);
@@ -1707,21 +2510,208 @@ let JupiterDynamicForm = class extends LitElement {
1707
2510
  }));
1708
2511
  }
1709
2512
  _handleColumnRemove(event) {
1710
- const { columnId } = event.detail;
1711
- this._columns = this._columns.filter((col) => col.id !== columnId);
1712
- for (const conceptId in this._formData) {
1713
- if (this._formData[conceptId][columnId] !== void 0) {
1714
- delete this._formData[conceptId][columnId];
2513
+ const { columnId, sectionId } = event.detail;
2514
+ if (this._currentSchema && sectionId) {
2515
+ const targetSection = this._currentSchema.sections.find((section) => section.id === sectionId);
2516
+ if (targetSection && targetSection.columns) {
2517
+ targetSection.columns = targetSection.columns.filter((col) => col.id !== columnId);
2518
+ }
2519
+ } else {
2520
+ this._columns = this._columns.filter((col) => col.id !== columnId);
2521
+ if (this._currentSchema) {
2522
+ this._currentSchema.sections.forEach((section) => {
2523
+ if (section.columns) {
2524
+ section.columns = section.columns.filter((col) => col.id !== columnId);
2525
+ }
2526
+ });
1715
2527
  }
1716
2528
  }
2529
+ this._removeColumnData(columnId, sectionId);
1717
2530
  this._dirty = true;
1718
2531
  this._validateForm();
1719
2532
  this.requestUpdate();
1720
2533
  this.dispatchEvent(new CustomEvent("column-remove", {
1721
- detail: { columnId },
2534
+ detail: { columnId, sectionId },
2535
+ bubbles: true
2536
+ }));
2537
+ }
2538
+ _handleColumnAddRequest(event) {
2539
+ const { sectionId, columnRequest } = event.detail;
2540
+ this._addColumnFromRequest(columnRequest, sectionId);
2541
+ }
2542
+ _addColumnFromRequest(request, sectionId) {
2543
+ var _a, _b, _c, _d, _e;
2544
+ const timestamp = Date.now();
2545
+ const newColumnId = `col-${timestamp}`;
2546
+ let title = "";
2547
+ let description = "";
2548
+ if (request.periodType === "instant") {
2549
+ title = request.instantDate || "Instant Date";
2550
+ description = `Instant period: ${request.instantDate}`;
2551
+ } else if (request.periodType === "duration" || request.periodType === "mixed") {
2552
+ title = `${request.startDate} / ${request.endDate}`;
2553
+ description = `Duration period: ${request.startDate} to ${request.endDate}`;
2554
+ }
2555
+ let dimensionData = {
2556
+ dimensionId: "period",
2557
+ memberValue: request.periodType === "instant" ? `instant-${request.instantDate}` : `duration-${request.startDate}-${request.endDate}`,
2558
+ memberLabel: title
2559
+ };
2560
+ if ((_b = (_a = this.xbrlInput) == null ? void 0 : _a.hypercubes) == null ? void 0 : _b[0]) {
2561
+ const hypercubeRole = this.xbrlInput.hypercubes[0].roles.find((hr) => hr.roleId === sectionId);
2562
+ if (((_c = hypercubeRole == null ? void 0 : hypercubeRole.items) == null ? void 0 : _c.length) === 1) {
2563
+ const item = hypercubeRole.items[0];
2564
+ if (item.dimensions.length === 1) {
2565
+ const dimension = item.dimensions[0];
2566
+ if (dimension.members.length > 0) {
2567
+ const axisLabel = ((_d = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _d.label) || dimension.conceptName;
2568
+ const firstMember = dimension.members[0];
2569
+ const memberLabel = ((_e = firstMember.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _e.label) || firstMember.conceptName;
2570
+ const periodPart = request.periodType === "instant" ? `(${request.instantDate})` : `(${request.startDate} / ${request.endDate})`;
2571
+ title = `${memberLabel} ${periodPart}`;
2572
+ dimensionData = {
2573
+ dimensionId: newColumnId,
2574
+ axisId: dimension.id,
2575
+ memberId: firstMember.id,
2576
+ memberValue: memberLabel,
2577
+ memberLabel,
2578
+ axis: axisLabel,
2579
+ axisLabel,
2580
+ memberKey: `${axisLabel} | ${memberLabel}`,
2581
+ dimensionIdKey: `${dimension.id} | ${firstMember.id}`
2582
+ };
2583
+ console.log(`📊 Applied hypercube dimension to new column: ${dimensionData.memberKey}`);
2584
+ }
2585
+ }
2586
+ }
2587
+ }
2588
+ const newColumn = {
2589
+ id: newColumnId,
2590
+ title,
2591
+ description,
2592
+ type: dimensionData.memberKey ? "dimension" : "dimension",
2593
+ order: this._columns.length,
2594
+ removable: true,
2595
+ dimensionData
2596
+ };
2597
+ if (this._currentSchema) {
2598
+ const targetSection = this._currentSchema.sections.find((section) => section.id === sectionId);
2599
+ if (targetSection) {
2600
+ if (!targetSection.columns) {
2601
+ targetSection.columns = [...this._columns];
2602
+ }
2603
+ targetSection.columns = [...targetSection.columns, newColumn];
2604
+ }
2605
+ }
2606
+ this._replicateFieldsForNewColumn(newColumnId, request, sectionId);
2607
+ this._dirty = true;
2608
+ this.requestUpdate();
2609
+ this.dispatchEvent(new CustomEvent("column-add", {
2610
+ detail: { column: newColumn },
1722
2611
  bubbles: true
1723
2612
  }));
1724
2613
  }
2614
+ _removeColumnData(columnId, sectionId) {
2615
+ if (!this._currentSchema)
2616
+ return;
2617
+ if (sectionId) {
2618
+ const targetSection = this._currentSchema.sections.find((section) => section.id === sectionId);
2619
+ if (targetSection) {
2620
+ this._removeColumnDataFromConcepts(targetSection.concepts, columnId);
2621
+ }
2622
+ } else {
2623
+ for (const conceptId in this._formData) {
2624
+ if (this._formData[conceptId][columnId] !== void 0) {
2625
+ delete this._formData[conceptId][columnId];
2626
+ }
2627
+ }
2628
+ }
2629
+ }
2630
+ _removeColumnDataFromConcepts(concepts, columnId) {
2631
+ concepts.forEach((concept) => {
2632
+ if (this._formData[concept.id] && this._formData[concept.id][columnId] !== void 0) {
2633
+ delete this._formData[concept.id][columnId];
2634
+ }
2635
+ if (concept.fields) {
2636
+ concept.fields = concept.fields.filter((field) => field.columnId !== columnId);
2637
+ }
2638
+ if (concept.children) {
2639
+ this._removeColumnDataFromConcepts(concept.children, columnId);
2640
+ }
2641
+ });
2642
+ }
2643
+ _shouldCreateFieldForConcept(concept, request) {
2644
+ if (concept.abstract) {
2645
+ return false;
2646
+ }
2647
+ if (concept.periodType) {
2648
+ if (request.periodType === "instant" && concept.periodType !== "instant") {
2649
+ return false;
2650
+ }
2651
+ if (request.periodType === "duration" && concept.periodType !== "duration") {
2652
+ return false;
2653
+ }
2654
+ }
2655
+ return true;
2656
+ }
2657
+ _replicateFieldsForNewColumn(columnId, request, sectionId) {
2658
+ if (!this._currentSchema)
2659
+ return;
2660
+ const formBuilder = new XBRLFormBuilder();
2661
+ const targetSection = this._currentSchema.sections.find((section) => section.id === sectionId);
2662
+ if (targetSection) {
2663
+ this._replicateFieldsForSection(targetSection.concepts, columnId, request, formBuilder);
2664
+ }
2665
+ }
2666
+ _replicateFieldsForSection(concepts, columnId, request, formBuilder) {
2667
+ concepts.forEach((concept) => {
2668
+ var _a;
2669
+ if (this._shouldCreateFieldForConcept(concept, request)) {
2670
+ const existingField = (_a = concept.fields) == null ? void 0 : _a[0];
2671
+ let field;
2672
+ if (existingField) {
2673
+ field = {
2674
+ id: `${concept.id}_${columnId}`,
2675
+ conceptId: concept.id,
2676
+ columnId,
2677
+ type: existingField.type,
2678
+ label: existingField.label,
2679
+ placeholder: existingField.placeholder,
2680
+ required: existingField.required,
2681
+ disabled: existingField.disabled,
2682
+ validation: existingField.validation,
2683
+ defaultValue: existingField.defaultValue,
2684
+ // Set period dates from the add column request
2685
+ periodStartDate: request.periodType === "instant" ? request.instantDate : request.startDate,
2686
+ periodEndDate: request.periodType === "instant" ? request.instantDate : request.endDate
2687
+ };
2688
+ } else {
2689
+ field = {
2690
+ id: `${concept.id}_${columnId}`,
2691
+ conceptId: concept.id,
2692
+ columnId,
2693
+ type: "text",
2694
+ label: concept.label || concept.name,
2695
+ placeholder: `Enter ${concept.name}`,
2696
+ required: false,
2697
+ disabled: false,
2698
+ validation: [],
2699
+ defaultValue: "",
2700
+ // Set period dates from the add column request
2701
+ periodStartDate: request.periodType === "instant" ? request.instantDate : request.startDate,
2702
+ periodEndDate: request.periodType === "instant" ? request.instantDate : request.endDate
2703
+ };
2704
+ }
2705
+ if (!concept.fields) {
2706
+ concept.fields = [];
2707
+ }
2708
+ concept.fields.push(field);
2709
+ }
2710
+ if (concept.children) {
2711
+ this._replicateFieldsForSection(concept.children, columnId, request, formBuilder);
2712
+ }
2713
+ });
2714
+ }
1725
2715
  _addColumn() {
1726
2716
  const newColumnId = `dim-${Date.now()}`;
1727
2717
  const newColumn = {
@@ -1747,15 +2737,95 @@ let JupiterDynamicForm = class extends LitElement {
1747
2737
  _handleSubmit() {
1748
2738
  this._submitted = true;
1749
2739
  this._validateForm();
2740
+ const submissionData = this._generateSubmissionData();
1750
2741
  this.dispatchEvent(new CustomEvent("form-submit", {
1751
2742
  detail: {
1752
2743
  data: this._formData,
2744
+ submissionData,
2745
+ valid: this._valid,
2746
+ errors: this._errors
2747
+ },
2748
+ bubbles: true
2749
+ }));
2750
+ }
2751
+ _handleSaveDraft() {
2752
+ const draftData = this._generateSubmissionData();
2753
+ this.dispatchEvent(new CustomEvent("form-save-draft", {
2754
+ detail: {
2755
+ data: this._formData,
2756
+ draftData,
1753
2757
  valid: this._valid,
1754
2758
  errors: this._errors
1755
2759
  },
1756
2760
  bubbles: true
1757
2761
  }));
1758
2762
  }
2763
+ _generateSubmissionData() {
2764
+ const submissionData = [];
2765
+ if (!this._currentSchema) {
2766
+ return submissionData;
2767
+ }
2768
+ this._currentSchema.sections.forEach((section) => {
2769
+ this._processConceptsForSubmission(section.concepts, submissionData, section);
2770
+ });
2771
+ return submissionData;
2772
+ }
2773
+ _findColumnById(columnId) {
2774
+ if (!this._currentSchema) {
2775
+ return void 0;
2776
+ }
2777
+ for (const section of this._currentSchema.sections) {
2778
+ if (section.columns) {
2779
+ const column = section.columns.find((col) => col.id === columnId);
2780
+ if (column) {
2781
+ return column;
2782
+ }
2783
+ }
2784
+ }
2785
+ return void 0;
2786
+ }
2787
+ _processConceptsForSubmission(concepts, submissionData, section) {
2788
+ concepts.forEach((concept) => {
2789
+ if (concept.fields && concept.fields.length > 0) {
2790
+ concept.fields.forEach((field) => {
2791
+ var _a, _b, _c;
2792
+ const conceptData = this._formData[concept.id];
2793
+ const fieldValue = conceptData == null ? void 0 : conceptData[field.columnId];
2794
+ if (fieldValue !== void 0 && fieldValue !== null && fieldValue !== "") {
2795
+ const column = this._findColumnById(field.columnId);
2796
+ const submissionEntry = {
2797
+ conceptId: concept.id,
2798
+ value: fieldValue,
2799
+ period: {
2800
+ type: concept.periodType || "duration"
2801
+ }
2802
+ };
2803
+ if (concept.periodType === "instant") {
2804
+ submissionEntry.period.date = field.periodStartDate || this.periodStartDate;
2805
+ } else {
2806
+ submissionEntry.period.startDate = field.periodStartDate || this.periodStartDate;
2807
+ submissionEntry.period.endDate = field.periodEndDate || this.periodEndDate;
2808
+ }
2809
+ if ((column == null ? void 0 : column.type) === "dimension" && ((_a = column.dimensionData) == null ? void 0 : _a.dimensionIdKey)) {
2810
+ submissionEntry.dimension = column.dimensionData.dimensionIdKey;
2811
+ } else if ((_b = section == null ? void 0 : section.columns) == null ? void 0 : _b.length) {
2812
+ const sectionDimensionColumn = section.columns.find((col) => {
2813
+ var _a2;
2814
+ return col.type === "dimension" && ((_a2 = col.dimensionData) == null ? void 0 : _a2.dimensionIdKey);
2815
+ });
2816
+ if ((_c = sectionDimensionColumn == null ? void 0 : sectionDimensionColumn.dimensionData) == null ? void 0 : _c.dimensionIdKey) {
2817
+ submissionEntry.dimension = sectionDimensionColumn.dimensionData.dimensionIdKey;
2818
+ }
2819
+ }
2820
+ submissionData.push(submissionEntry);
2821
+ }
2822
+ });
2823
+ }
2824
+ if (concept.children) {
2825
+ this._processConceptsForSubmission(concept.children, submissionData, section);
2826
+ }
2827
+ });
2828
+ }
1759
2829
  _handleReset() {
1760
2830
  this._formData = { ...this.initialData };
1761
2831
  this._touched.clear();
@@ -1816,19 +2886,6 @@ let JupiterDynamicForm = class extends LitElement {
1816
2886
  ` : ""}
1817
2887
  </div>
1818
2888
 
1819
- <!-- Add Column Section -->
1820
- ${config.enableColumnManagement !== false ? html`
1821
- <div class="add-column-container">
1822
- <button
1823
- class="add-column-btn"
1824
- @click="${this._addColumn}"
1825
- ?disabled="${this.disabled || this.readonly || config.maxColumns && this._columns.length >= config.maxColumns}"
1826
- >
1827
- Add Dimension Column
1828
- </button>
1829
- </div>
1830
- ` : ""}
1831
-
1832
2889
  <!-- Form Content -->
1833
2890
  <div class="form-sections">
1834
2891
  <!-- Validation Summary -->
@@ -1847,7 +2904,7 @@ let JupiterDynamicForm = class extends LitElement {
1847
2904
  ${schema.sections.map((section) => html`
1848
2905
  <jupiter-form-section
1849
2906
  .section="${section}"
1850
- .columns="${this._columns}"
2907
+ .columns="${section.columns || this._columns}"
1851
2908
  .formData="${this._formData}"
1852
2909
  .disabled="${this.disabled || this.readonly}"
1853
2910
  .collapsible="${config.collapsibleSections !== false}"
@@ -1856,26 +2913,27 @@ let JupiterDynamicForm = class extends LitElement {
1856
2913
  @section-expand="${this._handleSectionExpand}"
1857
2914
  @concept-expand="${this._handleConceptExpand}"
1858
2915
  @column-remove="${this._handleColumnRemove}"
2916
+ @column-add-request="${this._handleColumnAddRequest}"
1859
2917
  ></jupiter-form-section>
1860
2918
  `)}
1861
2919
  </div>
1862
2920
 
1863
- <!-- Form Actions -->
2921
+ <!-- Form Actions - Fixed Footer -->
1864
2922
  <div class="form-actions">
1865
2923
  <button
1866
- class="btn-primary"
1867
- @click="${this._handleSubmit}"
2924
+ class="btn-secondary"
2925
+ @click="${this._handleSaveDraft}"
1868
2926
  ?disabled="${this.disabled || this.readonly}"
1869
2927
  >
1870
- Submit
2928
+ Save Draft
1871
2929
  </button>
1872
2930
 
1873
2931
  <button
1874
- class="btn-outline"
1875
- @click="${this._handleReset}"
1876
- ?disabled="${this.disabled || !this._dirty}"
2932
+ class="btn-primary"
2933
+ @click="${this._handleSubmit}"
2934
+ ?disabled="${this.disabled || this.readonly}"
1877
2935
  >
1878
- Reset
2936
+ Submit
1879
2937
  </button>
1880
2938
 
1881
2939
  <div class="form-meta">
@@ -1923,42 +2981,23 @@ JupiterDynamicForm.styles = css`
1923
2981
  }
1924
2982
 
1925
2983
  .form-actions {
2984
+ position: fixed;
2985
+ bottom: 0;
2986
+ left: 0;
2987
+ right: 0;
1926
2988
  padding: 16px 24px;
1927
2989
  border-top: 1px solid var(--jupiter-border-color, #ddd);
1928
2990
  background: var(--jupiter-form-actions-background, #f8f9fa);
1929
2991
  display: flex;
1930
2992
  gap: 12px;
1931
2993
  align-items: center;
1932
- }
1933
-
1934
- .add-column-container {
1935
- padding: 16px 24px;
1936
- border-bottom: 1px solid var(--jupiter-border-color, #ddd);
1937
- background: var(--jupiter-form-actions-background, #f8f9fa);
1938
- }
1939
-
1940
- .add-column-btn {
1941
- padding: 8px 16px;
1942
- background: var(--jupiter-primary-color, #1976d2);
1943
- color: white;
1944
- border: none;
1945
- border-radius: 4px;
1946
- cursor: pointer;
1947
- font-size: 14px;
1948
- font-weight: 500;
1949
- }
1950
-
1951
- .add-column-btn:hover {
1952
- background: var(--jupiter-primary-color-dark, #1565c0);
1953
- }
1954
-
1955
- .add-column-btn:disabled {
1956
- background: var(--jupiter-disabled-background, #ccc);
1957
- cursor: not-allowed;
2994
+ z-index: 1000;
2995
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
1958
2996
  }
1959
2997
 
1960
2998
  .form-sections {
1961
2999
  padding: 24px;
3000
+ padding-bottom: 100px; /* Add space for fixed footer */
1962
3001
  }
1963
3002
 
1964
3003
  .validation-summary {
@@ -2092,6 +3131,7 @@ JupiterDynamicForm = __decorateClass([
2092
3131
  const version = "1.0.0";
2093
3132
  export {
2094
3133
  FormValidator,
3134
+ JupiterAddColumnDialog,
2095
3135
  JupiterConceptTree,
2096
3136
  JupiterDynamicForm,
2097
3137
  JupiterFormField,