jupiter-dynamic-forms 1.2.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,32 @@ 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);
538
552
  this.assignFieldColumnIds(section);
539
553
  sections.push(section);
540
554
  });
@@ -549,19 +563,30 @@ class XBRLFormBuilder {
549
563
  /**
550
564
  * Build a form section from a presentation role
551
565
  */
552
- static buildSectionFromRole(role, periodStartDate, periodEndDate) {
566
+ static buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData) {
553
567
  var _a;
554
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 };
555
574
  const conceptTrees = [];
556
575
  if ((_a = role.presentationLinkbase) == null ? void 0 : _a.concepts) {
557
576
  role.presentationLinkbase.concepts.forEach((concept) => {
558
- const conceptTree = this.buildConceptTree(concept, 0, periodStartDate, periodEndDate);
577
+ const conceptTree = this.buildConceptTree(concept, 0, periodStartDate, periodEndDate, roleInfo);
559
578
  if (conceptTree) {
560
579
  conceptTrees.push(conceptTree);
561
580
  }
562
581
  });
563
582
  }
564
- const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31");
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);
565
590
  return {
566
591
  id: role.id,
567
592
  title,
@@ -574,52 +599,78 @@ class XBRLFormBuilder {
574
599
  /**
575
600
  * Build concept tree from XBRL presentation concept
576
601
  */
577
- static buildConceptTree(concept, level, periodStartDate, periodEndDate) {
602
+ static buildConceptTree(concept, level, periodStartDate, periodEndDate, roleInfo) {
578
603
  const label = this.getPreferredLabel(concept.labels);
579
604
  const fields = [];
580
605
  if (!concept.elementAbstract) {
581
- const field = this.createFieldFromConcept(concept, periodStartDate, periodEndDate);
582
- if (field) {
583
- 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);
584
626
  }
585
627
  }
586
628
  const children = [];
587
629
  if (concept.children && concept.children.length > 0) {
588
630
  concept.children.forEach((child) => {
589
- const childTree = this.buildConceptTree(child, level + 1, periodStartDate, periodEndDate);
631
+ const childTree = this.buildConceptTree(child, level + 1, periodStartDate, periodEndDate, roleInfo);
590
632
  if (childTree) {
591
633
  children.push(childTree);
592
634
  }
593
635
  });
594
636
  }
595
637
  return {
596
- 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
597
642
  name: concept.conceptName,
598
643
  label,
599
644
  description: `${concept.conceptName} (${concept.type})`,
600
645
  level,
601
646
  children,
602
647
  fields,
603
- collapsed: level > 0
648
+ collapsed: level > 0,
604
649
  // Collapse nested levels by default
650
+ abstract: concept.elementAbstract,
651
+ periodType: concept.periodType
605
652
  };
606
653
  }
607
654
  /**
608
655
  * Create form field from XBRL concept
609
656
  */
610
- static createFieldFromConcept(concept, periodStartDate, periodEndDate) {
657
+ static createFieldFromConcept(concept, periodStartDate, periodEndDate, forcedColumnId) {
611
658
  const fieldType = this.mapXBRLTypeToFieldType(concept.type);
612
659
  const label = this.getPreferredLabel(concept.labels);
613
- let columnId = "default";
614
- if (concept.periodType === "instant") {
615
- columnId = "instant";
616
- } else if (concept.periodType === "duration") {
617
- columnId = "duration_start";
660
+ let columnId;
661
+ if (forcedColumnId) {
662
+ columnId = forcedColumnId;
618
663
  } else {
619
- columnId = "default";
664
+ if (concept.periodType === "instant") {
665
+ columnId = "instant";
666
+ } else if (concept.periodType === "duration") {
667
+ columnId = "duration";
668
+ } else {
669
+ columnId = "default";
670
+ }
620
671
  }
621
672
  const field = {
622
- id: `${concept.id}_field`,
673
+ id: `${concept.id}_${columnId}_field`,
623
674
  conceptId: concept.id,
624
675
  columnId,
625
676
  type: fieldType,
@@ -686,16 +737,8 @@ class XBRLFormBuilder {
686
737
  * Recursively assign column IDs to fields in a concept tree
687
738
  */
688
739
  static assignColumnIdsToConceptFields(conceptTree, columnIds) {
689
- conceptTree.fields.forEach((field) => {
690
- if (columnIds.includes("instant") && field.columnId === "instant") {
691
- field.columnId = "instant";
692
- } else if (columnIds.includes("duration_start") && field.columnId === "duration_start") {
693
- field.columnId = "duration_start";
694
- } else if (columnIds.includes("period_start") && (field.columnId === "duration_start" || field.columnId === "instant")) {
695
- field.columnId = "period_start";
696
- } else if (columnIds.length > 0) {
697
- field.columnId = columnIds[0];
698
- }
740
+ conceptTree.fields = conceptTree.fields.filter((field) => {
741
+ return columnIds.includes(field.columnId);
699
742
  });
700
743
  if (conceptTree.children) {
701
744
  conceptTree.children.forEach((child) => {
@@ -703,6 +746,18 @@ class XBRLFormBuilder {
703
746
  });
704
747
  }
705
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
+ }
706
761
  /**
707
762
  * Get all non-abstract concepts from a role recursively
708
763
  */
@@ -732,10 +787,14 @@ class XBRLFormBuilder {
732
787
  /**
733
788
  * Generate default columns based on period types of non-abstract concepts in a role
734
789
  */
735
- static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate) {
736
- const nonAbstractConcepts = this.getAllNonAbstractConcepts(role);
737
- console.log(`📊 Analyzing role "${role.role}" with ${nonAbstractConcepts.length} non-abstract concepts`);
738
- if (nonAbstractConcepts.length === 0) {
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) {
739
798
  console.log("📊 No non-abstract concepts found, using default column");
740
799
  return [{
741
800
  id: "default",
@@ -746,67 +805,135 @@ class XBRLFormBuilder {
746
805
  removable: false
747
806
  }];
748
807
  }
749
- const periodTypes = new Set(
750
- nonAbstractConcepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
751
- );
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
+ }
752
843
  console.log(`📅 Found period types: ${Array.from(periodTypes).join(", ")}`);
753
844
  const columns = [];
754
845
  if (periodTypes.size === 0) {
755
846
  console.log("📅 No period types found, using default column");
847
+ const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel}` : "Value";
756
848
  columns.push({
757
849
  id: "default",
758
- title: "Value",
850
+ title: columnTitle,
759
851
  description: "Default value column",
760
- type: "base",
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,
761
864
  order: 0,
762
865
  removable: false
763
866
  });
764
867
  } else if (periodTypes.size === 1 && periodTypes.has("instant")) {
765
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)}`;
766
870
  columns.push({
767
871
  id: "instant",
768
- title: `As of ${this.formatDateForDisplay(periodStartDate)}`,
872
+ title: columnTitle,
769
873
  description: `Values as of ${periodStartDate}`,
770
- type: "base",
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,
771
886
  order: 0,
772
887
  removable: false
773
888
  });
774
889
  } else if (periodTypes.size === 1 && periodTypes.has("duration")) {
775
- console.log("📅 All concepts are duration type, creating two columns");
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)}`;
776
892
  columns.push({
777
- id: "duration_start",
778
- title: `From ${this.formatDateForDisplay(periodStartDate)}`,
779
- description: `Period start: ${periodStartDate}`,
780
- type: "base",
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,
781
908
  order: 0,
782
909
  removable: false
783
910
  });
784
- columns.push({
785
- id: "duration_end",
786
- title: `To ${this.formatDateForDisplay(periodEndDate)}`,
787
- description: `Period end: ${periodEndDate}`,
788
- type: "base",
789
- order: 1,
790
- removable: false
791
- });
911
+ console.log("📅 Created duration column:", columns.map((c2) => ({ id: c2.id, title: c2.title })));
792
912
  } else {
793
- console.log("📅 Mixed period types found, creating two columns for full range");
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)}`;
794
915
  columns.push({
795
- id: "period_start",
796
- title: `From ${this.formatDateForDisplay(periodStartDate)}`,
797
- description: `Period start: ${periodStartDate}`,
798
- type: "base",
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,
799
931
  order: 0,
800
932
  removable: false
801
933
  });
802
- columns.push({
803
- id: "period_end",
804
- title: `To ${this.formatDateForDisplay(periodEndDate)}`,
805
- description: `Period end: ${periodEndDate}`,
806
- type: "base",
807
- order: 1,
808
- removable: false
809
- });
934
+ }
935
+ if (dimensionInfo) {
936
+ console.log(`📊 Applied dimension to ${columns.length} columns: ${dimensionInfo.dimensionKey}`);
810
937
  }
811
938
  console.log(`📊 Generated ${columns.length} columns for role "${role.role}":`, columns.map((c2) => c2.title));
812
939
  return columns;
@@ -864,15 +991,15 @@ class XBRLFormBuilder {
864
991
  }];
865
992
  }
866
993
  }
867
- var __defProp$3 = Object.defineProperty;
868
- var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
869
- var __decorateClass$3 = (decorators, target, key, kind) => {
870
- 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;
871
998
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
872
999
  if (decorator = decorators[i2])
873
1000
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
874
1001
  if (kind && result)
875
- __defProp$3(target, key, result);
1002
+ __defProp$4(target, key, result);
876
1003
  return result;
877
1004
  };
878
1005
  let JupiterFormField = class extends LitElement {
@@ -881,6 +1008,7 @@ let JupiterFormField = class extends LitElement {
881
1008
  this.value = null;
882
1009
  this.disabled = false;
883
1010
  this.locale = "en-US";
1011
+ this.hideLabel = false;
884
1012
  this._errors = [];
885
1013
  this._touched = false;
886
1014
  }
@@ -949,10 +1077,14 @@ let JupiterFormField = class extends LitElement {
949
1077
  const hasErrors = this._errors.some((e2) => e2.severity === "error");
950
1078
  const hasWarnings = this._errors.some((e2) => e2.severity === "warning");
951
1079
  const cssClass = `field-input ${hasErrors ? "error" : hasWarnings ? "warning" : ""}`;
1080
+ const fieldId = `${this.conceptId}__${this.columnId}`;
1081
+ const fieldName = `data[${this.conceptId}][${this.columnId}]`;
952
1082
  switch (this.field.type) {
953
1083
  case "textarea":
954
1084
  return html`
955
1085
  <textarea
1086
+ id="${fieldId}"
1087
+ name="${fieldName}"
956
1088
  class="${cssClass}"
957
1089
  .value="${this.value || ""}"
958
1090
  ?disabled="${this.disabled || this.field.disabled}"
@@ -965,6 +1097,8 @@ let JupiterFormField = class extends LitElement {
965
1097
  case "select":
966
1098
  return html`
967
1099
  <select
1100
+ id="${fieldId}"
1101
+ name="${fieldName}"
968
1102
  class="${cssClass}"
969
1103
  .value="${this.value || ""}"
970
1104
  ?disabled="${this.disabled || this.field.disabled}"
@@ -988,6 +1122,8 @@ let JupiterFormField = class extends LitElement {
988
1122
  return html`
989
1123
  <div class="checkbox-container">
990
1124
  <input
1125
+ id="${fieldId}"
1126
+ name="${fieldName}"
991
1127
  type="checkbox"
992
1128
  class="field-input"
993
1129
  .checked="${Boolean(this.value)}"
@@ -1002,6 +1138,8 @@ let JupiterFormField = class extends LitElement {
1002
1138
  default:
1003
1139
  return html`
1004
1140
  <input
1141
+ id="${fieldId}"
1142
+ name="${fieldName}"
1005
1143
  type="${this._getInputType()}"
1006
1144
  class="${cssClass}"
1007
1145
  .value="${this.value || ""}"
@@ -1036,7 +1174,7 @@ let JupiterFormField = class extends LitElement {
1036
1174
  }
1037
1175
  }
1038
1176
  render() {
1039
- const showLabel = this.field.type !== "boolean";
1177
+ const showLabel = !this.hideLabel && this.field.type !== "boolean";
1040
1178
  return html`
1041
1179
  <div class="field-container">
1042
1180
  ${showLabel ? html`
@@ -1063,7 +1201,11 @@ let JupiterFormField = class extends LitElement {
1063
1201
  JupiterFormField.styles = css`
1064
1202
  :host {
1065
1203
  display: block;
1066
- margin-bottom: 8px;
1204
+ margin-bottom: 0px; /* Remove bottom margin for table layout */
1205
+ }
1206
+
1207
+ :host([hideLabel]) {
1208
+ margin-bottom: 0px;
1067
1209
  }
1068
1210
 
1069
1211
  .field-container {
@@ -1085,10 +1227,10 @@ JupiterFormField.styles = css`
1085
1227
 
1086
1228
  .field-input {
1087
1229
  width: 100%;
1088
- padding: 8px 12px;
1230
+ padding: 6px 8px; /* Reduced padding for table cells */
1089
1231
  border: 1px solid var(--jupiter-border-color, #ddd);
1090
1232
  border-radius: 4px;
1091
- font-size: 14px;
1233
+ font-size: 13px; /* Slightly smaller font for table */
1092
1234
  font-family: inherit;
1093
1235
  background: var(--jupiter-input-background, #fff);
1094
1236
  color: var(--jupiter-text-primary, #333);
@@ -1162,42 +1304,45 @@ JupiterFormField.styles = css`
1162
1304
  width: auto;
1163
1305
  }
1164
1306
  `;
1165
- __decorateClass$3([
1307
+ __decorateClass$4([
1166
1308
  n2({ type: Object })
1167
1309
  ], JupiterFormField.prototype, "field", 2);
1168
- __decorateClass$3([
1310
+ __decorateClass$4([
1169
1311
  n2({ type: String })
1170
1312
  ], JupiterFormField.prototype, "conceptId", 2);
1171
- __decorateClass$3([
1313
+ __decorateClass$4([
1172
1314
  n2({ type: String })
1173
1315
  ], JupiterFormField.prototype, "columnId", 2);
1174
- __decorateClass$3([
1316
+ __decorateClass$4([
1175
1317
  n2()
1176
1318
  ], JupiterFormField.prototype, "value", 2);
1177
- __decorateClass$3([
1319
+ __decorateClass$4([
1178
1320
  n2({ type: Boolean })
1179
1321
  ], JupiterFormField.prototype, "disabled", 2);
1180
- __decorateClass$3([
1322
+ __decorateClass$4([
1181
1323
  n2({ type: String })
1182
1324
  ], JupiterFormField.prototype, "locale", 2);
1183
- __decorateClass$3([
1325
+ __decorateClass$4([
1326
+ n2({ type: Boolean })
1327
+ ], JupiterFormField.prototype, "hideLabel", 2);
1328
+ __decorateClass$4([
1184
1329
  r()
1185
1330
  ], JupiterFormField.prototype, "_errors", 2);
1186
- __decorateClass$3([
1331
+ __decorateClass$4([
1187
1332
  r()
1188
1333
  ], JupiterFormField.prototype, "_touched", 2);
1189
- JupiterFormField = __decorateClass$3([
1334
+ JupiterFormField = __decorateClass$4([
1190
1335
  t$1("jupiter-form-field")
1191
1336
  ], JupiterFormField);
1192
- var __defProp$2 = Object.defineProperty;
1193
- var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
1194
- var __decorateClass$2 = (decorators, target, key, kind) => {
1195
- 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;
1196
1341
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
1197
1342
  if (decorator = decorators[i2])
1198
1343
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
1199
1344
  if (kind && result)
1200
- __defProp$2(target, key, result);
1345
+ __defProp$3(target, key, result);
1201
1346
  return result;
1202
1347
  };
1203
1348
  let JupiterConceptTree = class extends LitElement {
@@ -1207,11 +1352,18 @@ let JupiterConceptTree = class extends LitElement {
1207
1352
  this.formData = {};
1208
1353
  this.disabled = false;
1209
1354
  this.locale = "en-US";
1355
+ this.expandedConcepts = /* @__PURE__ */ new Set();
1210
1356
  this._expanded = true;
1211
1357
  }
1212
1358
  connectedCallback() {
1213
1359
  super.connectedCallback();
1214
- 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
+ }
1215
1367
  }
1216
1368
  _toggleExpanded() {
1217
1369
  this._expanded = !this._expanded;
@@ -1224,7 +1376,8 @@ let JupiterConceptTree = class extends LitElement {
1224
1376
  }));
1225
1377
  }
1226
1378
  _getFieldForColumn(columnId) {
1227
- 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);
1228
1381
  }
1229
1382
  _getFieldValue(field) {
1230
1383
  var _a;
@@ -1240,104 +1393,103 @@ let JupiterConceptTree = class extends LitElement {
1240
1393
  render() {
1241
1394
  const hasChildren = this.concept.children && this.concept.children.length > 0;
1242
1395
  const level = this.concept.level || 0;
1396
+ const isAbstract = this.concept.abstract || false;
1243
1397
  return html`
1244
- <div class="concept-row" style="--level: ${level}">
1245
- <!-- Concept Label Column -->
1246
- <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}">
1247
1401
  <div class="concept-indent"></div>
1248
- <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}">
1249
1404
  ${hasChildren ? "▶" : ""}
1250
1405
  </div>
1251
- <div class="concept-label">
1406
+ <div class="concept-label"
1407
+ @click="${this._toggleExpanded}"
1408
+ title="${this.concept.id}${this.concept.description ? " - " + this.concept.description : ""}">
1252
1409
  ${this.concept.label}
1253
- ${this.concept.description ? html`
1254
- <span class="concept-description">${this.concept.description}</span>
1255
- ` : ""}
1256
1410
  </div>
1257
1411
  </div>
1412
+ </td>
1258
1413
 
1259
- <!-- Field Columns -->
1260
- ${this.columns.map((column) => {
1414
+ <!-- Input Field Cells (Period Columns) - Only for non-abstract concepts -->
1415
+ ${this.columns.map((column) => {
1261
1416
  const field = this._getFieldForColumn(column.id);
1417
+ const shouldShowField = !isAbstract && field;
1262
1418
  return html`
1263
- <div class="field-cell ${!field ? "empty" : ""}">
1264
- ${field ? html`
1265
- <jupiter-form-field
1266
- .field="${field}"
1267
- .conceptId="${this.concept.id}"
1268
- .columnId="${column.id}"
1269
- .value="${this._getFieldValue(field)}"
1270
- .disabled="${this.disabled}"
1271
- .locale="${this.locale}"
1272
- @field-change="${this._handleFieldChange}"
1273
- ></jupiter-form-field>
1274
- ` : ""}
1275
- </div>
1276
- `;
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
+ `;
1277
1434
  })}
1278
- </div>
1279
-
1280
- <!-- Children Concepts -->
1281
- ${hasChildren ? html`
1282
- <div class="children ${!this._expanded ? "collapsed" : ""}">
1283
- ${this.concept.children.map((child) => html`
1284
- <jupiter-concept-tree
1285
- .concept="${child}"
1286
- .columns="${this.columns}"
1287
- .formData="${this.formData}"
1288
- .disabled="${this.disabled}"
1289
- .locale="${this.locale}"
1290
- @field-change="${this._handleFieldChange}"
1291
- @concept-expand="${(e2) => {
1292
- e2.stopPropagation();
1293
- this.dispatchEvent(new CustomEvent("concept-expand", { detail: e2.detail, bubbles: true }));
1294
- }}"
1295
- ></jupiter-concept-tree>
1296
- `)}
1297
- </div>
1298
- ` : ""}
1299
1435
  `;
1300
1436
  }
1301
1437
  };
1302
1438
  JupiterConceptTree.styles = css`
1303
1439
  :host {
1304
- display: block;
1305
- }
1306
-
1307
- .concept-row {
1440
+ /* Component renders table cells directly */
1308
1441
  display: contents;
1309
1442
  }
1310
1443
 
1311
- .concept-header {
1312
- display: flex;
1313
- align-items: center;
1314
- padding: 8px 12px;
1315
- background: var(--jupiter-concept-background, #f8f9fa);
1444
+ .concept-name-cell {
1445
+ vertical-align: top;
1446
+ padding: 2px 4px;
1316
1447
  border: 1px solid var(--jupiter-border-color, #ddd);
1317
1448
  border-bottom: none;
1318
- font-weight: 500;
1319
- cursor: pointer;
1320
- 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;
1456
+ }
1457
+
1458
+ .concept-name-cell.abstract {
1459
+ background: var(--jupiter-abstract-background, #f0f2f5);
1460
+ font-weight: 600;
1321
1461
  }
1322
1462
 
1323
- .concept-header:hover {
1324
- background: var(--jupiter-concept-hover-background, #e9ecef);
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;
1325
1476
  }
1326
1477
 
1327
1478
  .concept-indent {
1328
- width: calc(var(--level, 0) * 20px);
1479
+ width: calc(var(--level, 0) * 16px);
1329
1480
  flex-shrink: 0;
1330
1481
  }
1331
1482
 
1332
1483
  .concept-toggle {
1333
- width: 16px;
1334
- height: 16px;
1335
- margin-right: 8px;
1484
+ width: 14px;
1485
+ height: 14px;
1486
+ margin-right: 6px;
1336
1487
  display: flex;
1337
1488
  align-items: center;
1338
1489
  justify-content: center;
1339
- font-size: 12px;
1490
+ font-size: 10px;
1340
1491
  transition: transform 0.2s ease;
1492
+ cursor: pointer;
1341
1493
  }
1342
1494
 
1343
1495
  .concept-toggle.expanded {
@@ -1351,71 +1503,390 @@ JupiterConceptTree.styles = css`
1351
1503
  .concept-label {
1352
1504
  flex: 1;
1353
1505
  color: var(--jupiter-text-primary, #333);
1354
- }
1355
-
1356
- .concept-description {
1357
- font-size: 12px;
1358
- color: var(--jupiter-text-secondary, #666);
1359
- font-weight: normal;
1360
- margin-left: 8px;
1361
- }
1362
-
1363
- .concept-fields {
1364
- 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 */
1365
1512
  }
1366
1513
 
1367
1514
  .field-cell {
1515
+ vertical-align: middle;
1516
+ padding: 2px 6px;
1368
1517
  border: 1px solid var(--jupiter-border-color, #ddd);
1369
1518
  border-bottom: none;
1370
- padding: 8px;
1371
1519
  background: var(--jupiter-cell-background, #fff);
1372
- min-height: 40px;
1373
- display: flex;
1374
- align-items: center;
1375
- }
1376
-
1377
- .field-cell:last-child {
1378
- border-right: 1px solid var(--jupiter-border-color, #ddd);
1520
+ min-height: 28px;
1521
+ text-align: center;
1522
+ min-width: 180px;
1523
+ width: 180px;
1379
1524
  }
1380
1525
 
1381
1526
  .field-cell.empty {
1382
1527
  background: var(--jupiter-empty-cell-background, #f8f9fa);
1383
1528
  }
1384
1529
 
1385
- .children {
1386
- display: contents;
1530
+ .field-cell.abstract-row {
1531
+ background: var(--jupiter-abstract-cell-background, #f0f2f5);
1387
1532
  }
1388
1533
 
1389
- .children.collapsed {
1534
+ /* Children are rendered as separate table rows, not nested */
1535
+ .children-wrapper {
1390
1536
  display: none;
1391
1537
  }
1392
-
1393
- .concept-row:last-of-type .concept-header,
1394
- .concept-row:last-of-type .field-cell {
1395
- border-bottom: 1px solid var(--jupiter-border-color, #ddd);
1396
- }
1397
1538
  `;
1398
- __decorateClass$2([
1539
+ __decorateClass$3([
1399
1540
  n2({ type: Object })
1400
1541
  ], JupiterConceptTree.prototype, "concept", 2);
1401
- __decorateClass$2([
1542
+ __decorateClass$3([
1402
1543
  n2({ type: Array })
1403
1544
  ], JupiterConceptTree.prototype, "columns", 2);
1404
- __decorateClass$2([
1545
+ __decorateClass$3([
1405
1546
  n2({ type: Object })
1406
1547
  ], JupiterConceptTree.prototype, "formData", 2);
1407
- __decorateClass$2([
1548
+ __decorateClass$3([
1408
1549
  n2({ type: Boolean })
1409
1550
  ], JupiterConceptTree.prototype, "disabled", 2);
1410
- __decorateClass$2([
1551
+ __decorateClass$3([
1411
1552
  n2({ type: String })
1412
1553
  ], JupiterConceptTree.prototype, "locale", 2);
1413
- __decorateClass$2([
1554
+ __decorateClass$3([
1555
+ n2({ type: Set })
1556
+ ], JupiterConceptTree.prototype, "expandedConcepts", 2);
1557
+ __decorateClass$3([
1414
1558
  r()
1415
1559
  ], JupiterConceptTree.prototype, "_expanded", 2);
1416
- JupiterConceptTree = __decorateClass$2([
1560
+ JupiterConceptTree = __decorateClass$3([
1417
1561
  t$1("jupiter-concept-tree")
1418
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);
1419
1890
  var __defProp$1 = Object.defineProperty;
1420
1891
  var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
1421
1892
  var __decorateClass$1 = (decorators, target, key, kind) => {
@@ -1436,10 +1907,58 @@ let JupiterFormSection = class extends LitElement {
1436
1907
  this.collapsible = true;
1437
1908
  this.locale = "en-US";
1438
1909
  this._expanded = true;
1910
+ this._showAddColumnDialog = false;
1911
+ this._sectionPeriodType = "duration";
1912
+ this._expandedConcepts = /* @__PURE__ */ new Set();
1439
1913
  }
1440
1914
  connectedCallback() {
1441
1915
  super.connectedCallback();
1442
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;
1443
1962
  }
1444
1963
  _toggleExpanded() {
1445
1964
  if (!this.collapsible)
@@ -1455,7 +1974,58 @@ let JupiterFormSection = class extends LitElement {
1455
1974
  }
1456
1975
  _handleRemoveColumn(columnId) {
1457
1976
  this.dispatchEvent(new CustomEvent("column-remove", {
1458
- 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
+ },
1459
2029
  bubbles: true
1460
2030
  }));
1461
2031
  }
@@ -1466,8 +2036,26 @@ let JupiterFormSection = class extends LitElement {
1466
2036
  bubbles: true
1467
2037
  }));
1468
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
+ }
1469
2050
  _handleConceptExpand(event) {
1470
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();
1471
2059
  this.dispatchEvent(new CustomEvent("concept-expand", {
1472
2060
  detail: event.detail,
1473
2061
  bubbles: true
@@ -1514,7 +2102,7 @@ let JupiterFormSection = class extends LitElement {
1514
2102
  <div class="table-container">
1515
2103
  <table class="form-table">
1516
2104
  <thead class="table-header">
1517
- <tr>
2105
+ <tr class="header-row">
1518
2106
  <th class="header-cell concept-column">Concept</th>
1519
2107
  ${this.columns.map((column) => html`
1520
2108
  <th class="header-cell ${column.removable ? "removable" : ""}">
@@ -1532,24 +2120,43 @@ let JupiterFormSection = class extends LitElement {
1532
2120
  ` : ""}
1533
2121
  </th>
1534
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>
1535
2131
  </tr>
1536
2132
  </thead>
1537
2133
  <tbody class="table-body">
1538
- ${this.section.concepts.map((concept) => html`
1539
- <jupiter-concept-tree
1540
- .concept="${concept}"
1541
- .columns="${this.columns}"
1542
- .formData="${this.formData}"
1543
- .disabled="${this.disabled}"
1544
- .locale="${this.locale}"
1545
- @field-change="${this._handleFieldChange}"
1546
- @concept-expand="${this._handleConceptExpand}"
1547
- ></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>
1548
2147
  `)}
1549
2148
  </tbody>
1550
2149
  </table>
1551
2150
  </div>
1552
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>
1553
2160
  `;
1554
2161
  }
1555
2162
  };
@@ -1633,7 +2240,8 @@ JupiterFormSection.styles = css`
1633
2240
 
1634
2241
  .form-table {
1635
2242
  width: 100%;
1636
- border-collapse: collapse;
2243
+ border-collapse: separate;
2244
+ border-spacing: 0;
1637
2245
  background: var(--jupiter-table-background, #fff);
1638
2246
  }
1639
2247
 
@@ -1644,18 +2252,27 @@ JupiterFormSection.styles = css`
1644
2252
  z-index: 1;
1645
2253
  }
1646
2254
 
2255
+ .header-row {
2256
+ /* Table row - no special display needed */
2257
+ }
2258
+
1647
2259
  .header-cell {
1648
- padding: 12px;
2260
+ padding: 8px 12px;
1649
2261
  text-align: left;
1650
2262
  font-weight: 600;
1651
2263
  color: var(--jupiter-text-primary, #333);
1652
2264
  border: 1px solid var(--jupiter-border-color, #ddd);
1653
2265
  background: var(--jupiter-header-background, #f8f9fa);
1654
- min-width: 150px;
2266
+ min-width: 180px;
2267
+ width: 180px;
2268
+ font-size: 14px;
2269
+ vertical-align: middle;
1655
2270
  }
1656
2271
 
1657
2272
  .header-cell.concept-column {
2273
+ width: 300px;
1658
2274
  min-width: 300px;
2275
+ max-width: 300px;
1659
2276
  position: sticky;
1660
2277
  left: 0;
1661
2278
  z-index: 2;
@@ -1686,8 +2303,19 @@ JupiterFormSection.styles = css`
1686
2303
  background: var(--jupiter-error-color-dark, #b71c1c);
1687
2304
  }
1688
2305
 
1689
- .table-body {
1690
- 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);
1691
2319
  }
1692
2320
 
1693
2321
  .empty-section {
@@ -1718,6 +2346,15 @@ __decorateClass$1([
1718
2346
  __decorateClass$1([
1719
2347
  r()
1720
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);
1721
2358
  JupiterFormSection = __decorateClass$1([
1722
2359
  t$1("jupiter-form-section")
1723
2360
  ], JupiterFormSection);
@@ -1873,21 +2510,208 @@ let JupiterDynamicForm = class extends LitElement {
1873
2510
  }));
1874
2511
  }
1875
2512
  _handleColumnRemove(event) {
1876
- const { columnId } = event.detail;
1877
- this._columns = this._columns.filter((col) => col.id !== columnId);
1878
- for (const conceptId in this._formData) {
1879
- if (this._formData[conceptId][columnId] !== void 0) {
1880
- 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
+ });
1881
2527
  }
1882
2528
  }
2529
+ this._removeColumnData(columnId, sectionId);
1883
2530
  this._dirty = true;
1884
2531
  this._validateForm();
1885
2532
  this.requestUpdate();
1886
2533
  this.dispatchEvent(new CustomEvent("column-remove", {
1887
- detail: { columnId },
2534
+ detail: { columnId, sectionId },
1888
2535
  bubbles: true
1889
2536
  }));
1890
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 },
2611
+ bubbles: true
2612
+ }));
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
+ }
1891
2715
  _addColumn() {
1892
2716
  const newColumnId = `dim-${Date.now()}`;
1893
2717
  const newColumn = {
@@ -1913,15 +2737,95 @@ let JupiterDynamicForm = class extends LitElement {
1913
2737
  _handleSubmit() {
1914
2738
  this._submitted = true;
1915
2739
  this._validateForm();
2740
+ const submissionData = this._generateSubmissionData();
1916
2741
  this.dispatchEvent(new CustomEvent("form-submit", {
1917
2742
  detail: {
1918
2743
  data: this._formData,
2744
+ submissionData,
1919
2745
  valid: this._valid,
1920
2746
  errors: this._errors
1921
2747
  },
1922
2748
  bubbles: true
1923
2749
  }));
1924
2750
  }
2751
+ _handleSaveDraft() {
2752
+ const draftData = this._generateSubmissionData();
2753
+ this.dispatchEvent(new CustomEvent("form-save-draft", {
2754
+ detail: {
2755
+ data: this._formData,
2756
+ draftData,
2757
+ valid: this._valid,
2758
+ errors: this._errors
2759
+ },
2760
+ bubbles: true
2761
+ }));
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
+ }
1925
2829
  _handleReset() {
1926
2830
  this._formData = { ...this.initialData };
1927
2831
  this._touched.clear();
@@ -1982,19 +2886,6 @@ let JupiterDynamicForm = class extends LitElement {
1982
2886
  ` : ""}
1983
2887
  </div>
1984
2888
 
1985
- <!-- Add Column Section -->
1986
- ${config.enableColumnManagement !== false ? html`
1987
- <div class="add-column-container">
1988
- <button
1989
- class="add-column-btn"
1990
- @click="${this._addColumn}"
1991
- ?disabled="${this.disabled || this.readonly || config.maxColumns && this._columns.length >= config.maxColumns}"
1992
- >
1993
- Add Dimension Column
1994
- </button>
1995
- </div>
1996
- ` : ""}
1997
-
1998
2889
  <!-- Form Content -->
1999
2890
  <div class="form-sections">
2000
2891
  <!-- Validation Summary -->
@@ -2022,26 +2913,27 @@ let JupiterDynamicForm = class extends LitElement {
2022
2913
  @section-expand="${this._handleSectionExpand}"
2023
2914
  @concept-expand="${this._handleConceptExpand}"
2024
2915
  @column-remove="${this._handleColumnRemove}"
2916
+ @column-add-request="${this._handleColumnAddRequest}"
2025
2917
  ></jupiter-form-section>
2026
2918
  `)}
2027
2919
  </div>
2028
2920
 
2029
- <!-- Form Actions -->
2921
+ <!-- Form Actions - Fixed Footer -->
2030
2922
  <div class="form-actions">
2031
2923
  <button
2032
- class="btn-primary"
2033
- @click="${this._handleSubmit}"
2924
+ class="btn-secondary"
2925
+ @click="${this._handleSaveDraft}"
2034
2926
  ?disabled="${this.disabled || this.readonly}"
2035
2927
  >
2036
- Submit
2928
+ Save Draft
2037
2929
  </button>
2038
2930
 
2039
2931
  <button
2040
- class="btn-outline"
2041
- @click="${this._handleReset}"
2042
- ?disabled="${this.disabled || !this._dirty}"
2932
+ class="btn-primary"
2933
+ @click="${this._handleSubmit}"
2934
+ ?disabled="${this.disabled || this.readonly}"
2043
2935
  >
2044
- Reset
2936
+ Submit
2045
2937
  </button>
2046
2938
 
2047
2939
  <div class="form-meta">
@@ -2089,42 +2981,23 @@ JupiterDynamicForm.styles = css`
2089
2981
  }
2090
2982
 
2091
2983
  .form-actions {
2984
+ position: fixed;
2985
+ bottom: 0;
2986
+ left: 0;
2987
+ right: 0;
2092
2988
  padding: 16px 24px;
2093
2989
  border-top: 1px solid var(--jupiter-border-color, #ddd);
2094
2990
  background: var(--jupiter-form-actions-background, #f8f9fa);
2095
2991
  display: flex;
2096
2992
  gap: 12px;
2097
2993
  align-items: center;
2098
- }
2099
-
2100
- .add-column-container {
2101
- padding: 16px 24px;
2102
- border-bottom: 1px solid var(--jupiter-border-color, #ddd);
2103
- background: var(--jupiter-form-actions-background, #f8f9fa);
2104
- }
2105
-
2106
- .add-column-btn {
2107
- padding: 8px 16px;
2108
- background: var(--jupiter-primary-color, #1976d2);
2109
- color: white;
2110
- border: none;
2111
- border-radius: 4px;
2112
- cursor: pointer;
2113
- font-size: 14px;
2114
- font-weight: 500;
2115
- }
2116
-
2117
- .add-column-btn:hover {
2118
- background: var(--jupiter-primary-color-dark, #1565c0);
2119
- }
2120
-
2121
- .add-column-btn:disabled {
2122
- background: var(--jupiter-disabled-background, #ccc);
2123
- cursor: not-allowed;
2994
+ z-index: 1000;
2995
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
2124
2996
  }
2125
2997
 
2126
2998
  .form-sections {
2127
2999
  padding: 24px;
3000
+ padding-bottom: 100px; /* Add space for fixed footer */
2128
3001
  }
2129
3002
 
2130
3003
  .validation-summary {
@@ -2258,6 +3131,7 @@ JupiterDynamicForm = __decorateClass([
2258
3131
  const version = "1.0.0";
2259
3132
  export {
2260
3133
  FormValidator,
3134
+ JupiterAddColumnDialog,
2261
3135
  JupiterConceptTree,
2262
3136
  JupiterDynamicForm,
2263
3137
  JupiterFormField,