jupiter-dynamic-forms 1.18.0 → 1.18.2

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
@@ -620,7 +620,14 @@ class XBRLFormBuilder {
620
620
  */
621
621
  static buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData, language = "en", periodPreferences) {
622
622
  var _a, _b;
623
- const title = this.extractRoleTitle(role.role || role.id || "Unknown Role");
623
+ let title;
624
+ if (role.labels && role.labels.length > 0) {
625
+ const langLabel = role.labels.find((l2) => l2.lang === language);
626
+ const fallbackLabel = role.labels.find((l2) => l2.lang === "en") || role.labels[0];
627
+ title = (langLabel || fallbackLabel).label;
628
+ } else {
629
+ title = this.extractRoleTitle(role.role || role.id || "Unknown Role");
630
+ }
624
631
  const nonAbstractConcepts = this.getAllNonAbstractConcepts(role);
625
632
  const periodTypes = new Set(
626
633
  nonAbstractConcepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
@@ -631,7 +638,7 @@ class XBRLFormBuilder {
631
638
  console.log(`🔍 Filtering dimensions for role ${role.id} based on user selections`);
632
639
  hypercubeRole = this.filterHypercubeDimensionsBySelection(hypercubeRole, rolePreferences.dimensionSelections);
633
640
  }
634
- const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31", hypercubeRole, nonAbstractConcepts, periodTypes, rolePreferences);
641
+ const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31", hypercubeRole, nonAbstractConcepts, periodTypes, rolePreferences, language);
635
642
  const availableColumnIds = columns.map((col) => col.id);
636
643
  const roleInfo = { periodTypes, availableColumnIds, availableColumns: columns };
637
644
  const conceptTrees = [];
@@ -674,7 +681,7 @@ class XBRLFormBuilder {
674
681
  */
675
682
  static buildConceptTree(concept, level, periodStartDate, periodEndDate, roleInfo, sectionId, language = "en", conceptIdOccurrences, ancestorPeriodHint) {
676
683
  var _a, _b;
677
- const label = this.getPreferredLabel(concept.labels, language);
684
+ const label = this.getPreferredLabel(concept.labels, language, concept.preferredLabel);
678
685
  const childPeriodHint = ((_a = concept.preferredLabel) == null ? void 0 : _a.includes("periodStartLabel")) ? "start" : ((_b = concept.preferredLabel) == null ? void 0 : _b.includes("periodEndLabel")) ? "end" : ancestorPeriodHint;
679
686
  const fields = [];
680
687
  if (!concept.elementAbstract) {
@@ -754,7 +761,7 @@ class XBRLFormBuilder {
754
761
  static createFieldFromConcept(concept, periodStartDate, periodEndDate, forcedColumnId, ancestorPeriodHint, language = "en") {
755
762
  var _a;
756
763
  const fieldType = this.mapXBRLTypeToFieldType(concept.type);
757
- const label = this.getPreferredLabel(concept.labels, language);
764
+ const label = this.getPreferredLabel(concept.labels, language, concept.preferredLabel);
758
765
  let columnId;
759
766
  if (forcedColumnId) {
760
767
  columnId = forcedColumnId;
@@ -806,11 +813,19 @@ class XBRLFormBuilder {
806
813
  * @param labels - Array of XBRL labels
807
814
  * @param language - ISO language code (e.g., 'en', 'nl', 'de')
808
815
  */
809
- static getPreferredLabel(labels, language = "en") {
816
+ static getPreferredLabel(labels, language = "en", preferredRole) {
810
817
  if (!labels || labels.length === 0)
811
818
  return "Unnamed Concept";
812
819
  const languageLabels = labels.filter((l2) => l2.lang === language);
813
820
  const labelsToSearch = languageLabels.length > 0 ? languageLabels : labels;
821
+ if (preferredRole) {
822
+ const roleSpecificInLanguage = languageLabels.find((l2) => l2.role === preferredRole);
823
+ if (roleSpecificInLanguage)
824
+ return roleSpecificInLanguage.label;
825
+ const roleSpecificAnyLanguage = labels.find((l2) => l2.role === preferredRole);
826
+ if (roleSpecificAnyLanguage)
827
+ return roleSpecificAnyLanguage.label;
828
+ }
814
829
  const preferred = labelsToSearch.find((l2) => l2.preferredLabel);
815
830
  if (preferred)
816
831
  return preferred.label;
@@ -1002,7 +1017,7 @@ class XBRLFormBuilder {
1002
1017
  /**
1003
1018
  * Generate default columns based on period types of non-abstract concepts in a role
1004
1019
  */
1005
- static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate, hypercubeRole, nonAbstractConcepts, rolePeriodTypes, periodPreferences) {
1020
+ static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate, hypercubeRole, nonAbstractConcepts, rolePeriodTypes, periodPreferences, language = "en") {
1006
1021
  var _a, _b;
1007
1022
  const concepts = nonAbstractConcepts || this.getAllNonAbstractConcepts(role);
1008
1023
  const periodTypes = rolePeriodTypes || new Set(
@@ -1022,9 +1037,9 @@ class XBRLFormBuilder {
1022
1037
  if (((_a = hypercubeRole == null ? void 0 : hypercubeRole.items) == null ? void 0 : _a.length) === 1) {
1023
1038
  const item = hypercubeRole.items[0];
1024
1039
  if (item.dimensions.length === 1) {
1025
- dimensionColumns = this.generateSingleDimensionColumns(item.dimensions[0], periodStartDate, periodEndDate, periodTypes);
1040
+ dimensionColumns = this.generateSingleDimensionColumns(item.dimensions[0], periodStartDate, periodEndDate, periodTypes, language);
1026
1041
  } else if (item.dimensions.length > 1) {
1027
- dimensionColumns = this.generateMultiDimensionColumns(item.dimensions, periodStartDate, periodEndDate, periodTypes);
1042
+ dimensionColumns = this.generateMultiDimensionColumns(item.dimensions, periodStartDate, periodEndDate, periodTypes, language);
1028
1043
  }
1029
1044
  if (periodPreferences) {
1030
1045
  dimensionColumns = this.filterColumnsByPeriodPreferences(dimensionColumns, periodPreferences);
@@ -1156,10 +1171,9 @@ class XBRLFormBuilder {
1156
1171
  /**
1157
1172
  * Generate columns for single dimension scenarios
1158
1173
  */
1159
- static generateSingleDimensionColumns(dimension, periodStartDate, periodEndDate, periodTypes) {
1160
- var _a, _b, _c;
1174
+ static generateSingleDimensionColumns(dimension, periodStartDate, periodEndDate, periodTypes, language = "en") {
1161
1175
  if (dimension.typedMember && (!dimension.members || dimension.members.length === 0)) {
1162
- const axisLabel2 = ((_a = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _a.label) || dimension.conceptName;
1176
+ const axisLabel2 = this.getPreferredLabel(dimension.labels, language) || dimension.conceptName;
1163
1177
  const dimensionInfo2 = {
1164
1178
  axisId: dimension.id,
1165
1179
  axisLabel: axisLabel2,
@@ -1297,9 +1311,9 @@ class XBRLFormBuilder {
1297
1311
  if (dimension.members.length === 0) {
1298
1312
  return [];
1299
1313
  }
1300
- const axisLabel = ((_b = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _b.label) || dimension.conceptName;
1314
+ const axisLabel = this.getPreferredLabel(dimension.labels, language) || dimension.conceptName;
1301
1315
  const firstMember = dimension.members[0];
1302
- const memberLabel = ((_c = firstMember.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _c.label) || firstMember.conceptName;
1316
+ const memberLabel = this.getPreferredLabel(firstMember.labels, language) || firstMember.conceptName;
1303
1317
  const dimensionInfo = {
1304
1318
  axisId: dimension.id,
1305
1319
  axisLabel,
@@ -1403,7 +1417,7 @@ class XBRLFormBuilder {
1403
1417
  /**
1404
1418
  * Generate columns for multi-dimension scenarios - creates combinations of all dimension members
1405
1419
  */
1406
- static generateMultiDimensionColumns(dimensions, periodStartDate, periodEndDate, periodTypes) {
1420
+ static generateMultiDimensionColumns(dimensions, periodStartDate, periodEndDate, periodTypes, language = "en") {
1407
1421
  dimensions.some((dimension) => dimension.typedMember);
1408
1422
  const validDimensions = dimensions.filter((dimension) => {
1409
1423
  if (dimension.typedMember) {
@@ -1418,8 +1432,7 @@ class XBRLFormBuilder {
1418
1432
  return [];
1419
1433
  }
1420
1434
  const dimensionInfos = validDimensions.map((dimension) => {
1421
- var _a;
1422
- const axisLabel = ((_a = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _a.label) || dimension.conceptName;
1435
+ const axisLabel = this.getPreferredLabel(dimension.labels, language) || dimension.conceptName;
1423
1436
  if (dimension.typedMember) {
1424
1437
  return {
1425
1438
  id: dimension.id,
@@ -1437,13 +1450,10 @@ class XBRLFormBuilder {
1437
1450
  id: dimension.id,
1438
1451
  axisLabel,
1439
1452
  isTyped: false,
1440
- members: allMembers.map((member) => {
1441
- var _a2;
1442
- return {
1443
- id: member.id,
1444
- label: ((_a2 = member.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _a2.label) || member.conceptName
1445
- };
1446
- })
1453
+ members: allMembers.map((member) => ({
1454
+ id: member.id,
1455
+ label: this.getPreferredLabel(member.labels, language) || member.conceptName
1456
+ }))
1447
1457
  };
1448
1458
  });
1449
1459
  const combinations = this.generateDimensionCombinations(dimensionInfos);
@@ -2687,7 +2697,8 @@ const TYPE_INPUT_MAP = {
2687
2697
  // Monetary values without decimals (whole numbers only)
2688
2698
  "nl-types:monetaryNoDecimals20ItemType": {
2689
2699
  fieldType: "number",
2690
- htmlInputType: "number",
2700
+ htmlInputType: "text",
2701
+ inputMode: "decimal",
2691
2702
  allowDecimals: false,
2692
2703
  step: 1,
2693
2704
  placeholder: I18n.t("field.enterAmountNoDecimals")
@@ -2698,7 +2709,8 @@ const TYPE_INPUT_MAP = {
2698
2709
  // Monetary with decimals
2699
2710
  "xbrli:monetaryItemType": {
2700
2711
  fieldType: "currency",
2701
- htmlInputType: "number",
2712
+ htmlInputType: "text",
2713
+ inputMode: "decimal",
2702
2714
  allowDecimals: true,
2703
2715
  step: 0.01,
2704
2716
  placeholder: I18n.t("field.enterCurrency")
@@ -2721,14 +2733,16 @@ const TYPE_INPUT_MAP = {
2721
2733
  // Numeric types - integers
2722
2734
  "xbrli:integerItemType": {
2723
2735
  fieldType: "integer",
2724
- htmlInputType: "number",
2736
+ htmlInputType: "text",
2737
+ inputMode: "numeric",
2725
2738
  allowDecimals: false,
2726
2739
  step: 1,
2727
2740
  placeholder: I18n.t("field.enterWholeNumber")
2728
2741
  },
2729
2742
  "xbrli:nonNegativeIntegerItemType": {
2730
2743
  fieldType: "integer",
2731
- htmlInputType: "number",
2744
+ htmlInputType: "text",
2745
+ inputMode: "numeric",
2732
2746
  allowDecimals: false,
2733
2747
  min: 0,
2734
2748
  step: 1,
@@ -2736,7 +2750,8 @@ const TYPE_INPUT_MAP = {
2736
2750
  },
2737
2751
  "xbrli:positiveIntegerItemType": {
2738
2752
  fieldType: "integer",
2739
- htmlInputType: "number",
2753
+ htmlInputType: "text",
2754
+ inputMode: "numeric",
2740
2755
  allowDecimals: false,
2741
2756
  min: 1,
2742
2757
  step: 1,
@@ -2745,7 +2760,8 @@ const TYPE_INPUT_MAP = {
2745
2760
  // Numeric types - decimals
2746
2761
  "xbrli:decimalItemType": {
2747
2762
  fieldType: "decimal",
2748
- htmlInputType: "number",
2763
+ htmlInputType: "text",
2764
+ inputMode: "decimal",
2749
2765
  allowDecimals: true,
2750
2766
  step: "any",
2751
2767
  placeholder: I18n.t("field.enterDecimalValue")
@@ -2753,7 +2769,8 @@ const TYPE_INPUT_MAP = {
2753
2769
  // Shares (typically whole numbers or with limited decimals)
2754
2770
  "xbrli:sharesItemType": {
2755
2771
  fieldType: "number",
2756
- htmlInputType: "number",
2772
+ htmlInputType: "text",
2773
+ inputMode: "decimal",
2757
2774
  allowDecimals: true,
2758
2775
  min: 0,
2759
2776
  step: 0.01,
@@ -2761,7 +2778,8 @@ const TYPE_INPUT_MAP = {
2761
2778
  },
2762
2779
  "xbrli:shares": {
2763
2780
  fieldType: "number",
2764
- htmlInputType: "number",
2781
+ htmlInputType: "text",
2782
+ inputMode: "decimal",
2765
2783
  allowDecimals: true,
2766
2784
  min: 0,
2767
2785
  step: 0.01,
@@ -2770,7 +2788,8 @@ const TYPE_INPUT_MAP = {
2770
2788
  // Year (gYear)
2771
2789
  "xbrli:gYearItemType": {
2772
2790
  fieldType: "number",
2773
- htmlInputType: "number",
2791
+ htmlInputType: "text",
2792
+ inputMode: "numeric",
2774
2793
  allowDecimals: false,
2775
2794
  min: 1900,
2776
2795
  max: 2100,
@@ -2786,14 +2805,16 @@ const TYPE_INPUT_MAP = {
2786
2805
  // ==========================================
2787
2806
  "xbrli:pureItemType": {
2788
2807
  fieldType: "percentage",
2789
- htmlInputType: "number",
2808
+ htmlInputType: "text",
2809
+ inputMode: "decimal",
2790
2810
  allowDecimals: true,
2791
2811
  step: 0.01,
2792
2812
  placeholder: I18n.t("field.enterPercentage")
2793
2813
  },
2794
2814
  "xbrli:percentItemType": {
2795
2815
  fieldType: "percentage",
2796
- htmlInputType: "number",
2816
+ htmlInputType: "text",
2817
+ inputMode: "decimal",
2797
2818
  allowDecimals: true,
2798
2819
  step: 0.01,
2799
2820
  placeholder: I18n.t("field.enterPercentage")
@@ -2841,7 +2862,8 @@ function getInputTypeForConceptType(conceptType, datatypes) {
2841
2862
  if (lowerType.includes("nodecimals") || lowerType.includes("no-decimals")) {
2842
2863
  return {
2843
2864
  fieldType: "number",
2844
- htmlInputType: "number",
2865
+ htmlInputType: "text",
2866
+ inputMode: "decimal",
2845
2867
  allowDecimals: false,
2846
2868
  step: 1,
2847
2869
  placeholder: I18n.t("field.enterAmountNoDecimals")
@@ -2849,7 +2871,8 @@ function getInputTypeForConceptType(conceptType, datatypes) {
2849
2871
  }
2850
2872
  return {
2851
2873
  fieldType: "currency",
2852
- htmlInputType: "number",
2874
+ htmlInputType: "text",
2875
+ inputMode: "decimal",
2853
2876
  allowDecimals: true,
2854
2877
  step: 0.01,
2855
2878
  placeholder: I18n.t("field.enterCurrency")
@@ -2883,7 +2906,8 @@ function getInputTypeForConceptType(conceptType, datatypes) {
2883
2906
  const isPositive = lowerType.includes("positive");
2884
2907
  return {
2885
2908
  fieldType: "integer",
2886
- htmlInputType: "number",
2909
+ htmlInputType: "text",
2910
+ inputMode: "numeric",
2887
2911
  allowDecimals: false,
2888
2912
  min: isPositive ? 1 : isNonNegative ? 0 : void 0,
2889
2913
  step: 1,
@@ -2893,7 +2917,8 @@ function getInputTypeForConceptType(conceptType, datatypes) {
2893
2917
  if (lowerType.includes("decimal") || lowerType.includes("numeric") || lowerType.includes("number")) {
2894
2918
  return {
2895
2919
  fieldType: "decimal",
2896
- htmlInputType: "number",
2920
+ htmlInputType: "text",
2921
+ inputMode: "decimal",
2897
2922
  allowDecimals: true,
2898
2923
  step: "any",
2899
2924
  placeholder: I18n.t("field.enterDecimalValue")
@@ -2902,7 +2927,8 @@ function getInputTypeForConceptType(conceptType, datatypes) {
2902
2927
  if (lowerType.includes("percent") || lowerType.includes("pure")) {
2903
2928
  return {
2904
2929
  fieldType: "percentage",
2905
- htmlInputType: "number",
2930
+ htmlInputType: "text",
2931
+ inputMode: "decimal",
2906
2932
  allowDecimals: true,
2907
2933
  step: 0.01,
2908
2934
  placeholder: I18n.t("field.enterPercentage")
@@ -3018,7 +3044,8 @@ function determineInputTypeFromBaseChain(baseTypeChain, datatypes) {
3018
3044
  const isPositive = chainString.includes("positive");
3019
3045
  return {
3020
3046
  fieldType: "integer",
3021
- htmlInputType: "number",
3047
+ htmlInputType: "text",
3048
+ inputMode: "numeric",
3022
3049
  allowDecimals: false,
3023
3050
  min: isPositive ? 1 : isNonNegative ? 0 : void 0,
3024
3051
  step: 1,
@@ -3030,7 +3057,8 @@ function determineInputTypeFromBaseChain(baseTypeChain, datatypes) {
3030
3057
  if (chainString.includes("nodecimals") || chainString.includes("no-decimals") || chainString.includes("nodecimals20")) {
3031
3058
  return {
3032
3059
  fieldType: "number",
3033
- htmlInputType: "number",
3060
+ htmlInputType: "text",
3061
+ inputMode: "decimal",
3034
3062
  allowDecimals: false,
3035
3063
  step: 1,
3036
3064
  placeholder: I18n.t("field.enterAmountNoDecimals")
@@ -3038,7 +3066,8 @@ function determineInputTypeFromBaseChain(baseTypeChain, datatypes) {
3038
3066
  }
3039
3067
  return {
3040
3068
  fieldType: "currency",
3041
- htmlInputType: "number",
3069
+ htmlInputType: "text",
3070
+ inputMode: "decimal",
3042
3071
  allowDecimals: true,
3043
3072
  step: 0.01,
3044
3073
  placeholder: I18n.t("field.enterCurrency")
@@ -3046,7 +3075,8 @@ function determineInputTypeFromBaseChain(baseTypeChain, datatypes) {
3046
3075
  }
3047
3076
  return {
3048
3077
  fieldType: "decimal",
3049
- htmlInputType: "number",
3078
+ htmlInputType: "text",
3079
+ inputMode: "decimal",
3050
3080
  allowDecimals: true,
3051
3081
  step: "any",
3052
3082
  placeholder: I18n.t("field.enterDecimalValue")
@@ -3092,6 +3122,7 @@ let JupiterFormField = class extends LitElement {
3092
3122
  this._touched = false;
3093
3123
  this._showPeriodPopup = false;
3094
3124
  this._availableUnits = [];
3125
+ this._numericDraftValue = null;
3095
3126
  }
3096
3127
  willUpdate(changedProperties) {
3097
3128
  var _a;
@@ -3133,13 +3164,33 @@ let JupiterFormField = class extends LitElement {
3133
3164
  _isRoundingLevelConcept() {
3134
3165
  return !!this.conceptId && this.conceptId.includes("DocumentIntendedRoundingLevel");
3135
3166
  }
3167
+ _isNumericField() {
3168
+ var _a;
3169
+ const typeConfig = getInputTypeForConceptType(this.conceptType, this.datatypes);
3170
+ const effectiveFieldType = typeConfig.fieldType || ((_a = this.field) == null ? void 0 : _a.type) || "text";
3171
+ return isNumericType(effectiveFieldType) || this._getInputType() === "number";
3172
+ }
3173
+ _isIntermediateNumericValue(raw) {
3174
+ return raw === "-" || raw === "." || raw === "-.";
3175
+ }
3136
3176
  _handleInput(event) {
3137
3177
  const target = event.target;
3178
+ const oldValue = this.value;
3138
3179
  let value = target.value;
3139
- if (this.field.type === "number" || this.field.type === "decimal") {
3140
- value = value === "" ? null : Number(value);
3180
+ if (this._isNumericField()) {
3181
+ const rawValue = target.value;
3182
+ this._numericDraftValue = rawValue;
3183
+ if (rawValue === "" || this._isIntermediateNumericValue(rawValue)) {
3184
+ value = null;
3185
+ } else {
3186
+ const parsed = Number(rawValue);
3187
+ value = Number.isNaN(parsed) ? null : parsed;
3188
+ }
3141
3189
  } else if (this.field.type === "boolean") {
3142
3190
  value = target.checked;
3191
+ this._numericDraftValue = null;
3192
+ } else {
3193
+ this._numericDraftValue = null;
3143
3194
  }
3144
3195
  this.value = value;
3145
3196
  this._touched = true;
@@ -3149,7 +3200,7 @@ let JupiterFormField = class extends LitElement {
3149
3200
  conceptId: this.conceptId,
3150
3201
  columnId: this.columnId,
3151
3202
  value,
3152
- oldValue: this.value
3203
+ oldValue
3153
3204
  },
3154
3205
  bubbles: true
3155
3206
  }));
@@ -3165,6 +3216,16 @@ let JupiterFormField = class extends LitElement {
3165
3216
  }));
3166
3217
  }
3167
3218
  _handleBlur() {
3219
+ if (this._isNumericField() && this._numericDraftValue !== null) {
3220
+ const raw = this._numericDraftValue;
3221
+ if (raw === "" || this._isIntermediateNumericValue(raw)) {
3222
+ this.value = null;
3223
+ } else {
3224
+ const parsed = Number(raw);
3225
+ this.value = Number.isNaN(parsed) ? null : parsed;
3226
+ }
3227
+ this._numericDraftValue = null;
3228
+ }
3168
3229
  this._touched = true;
3169
3230
  this._validateXBRLDatatype();
3170
3231
  this._validateUnitSelection();
@@ -3205,7 +3266,7 @@ let JupiterFormField = class extends LitElement {
3205
3266
  */
3206
3267
  _handleKeyDown(event) {
3207
3268
  const target = event.target;
3208
- if (target.type !== "number") {
3269
+ if (!this._isNumericField()) {
3209
3270
  return;
3210
3271
  }
3211
3272
  const allowedKeys = [
@@ -3227,10 +3288,12 @@ let JupiterFormField = class extends LitElement {
3227
3288
  if (event.ctrlKey || event.metaKey) {
3228
3289
  return;
3229
3290
  }
3230
- if (event.key === "-" && target.selectionStart === 0 && !target.value.includes("-")) {
3291
+ const typeConfig = getInputTypeForConceptType(this.conceptType, this.datatypes);
3292
+ const allowNegative = typeConfig.min === void 0 || typeConfig.min < 0;
3293
+ if (event.key === "-" && allowNegative && !target.value.includes("-") && (target.selectionStart === 0 || target.value.length === 0)) {
3231
3294
  return;
3232
3295
  }
3233
- if (event.key === "." && !target.value.includes(".")) {
3296
+ if (event.key === "." && typeConfig.allowDecimals !== false && !target.value.includes(".")) {
3234
3297
  return;
3235
3298
  }
3236
3299
  if (event.key >= "0" && event.key <= "9") {
@@ -3666,7 +3729,7 @@ let JupiterFormField = class extends LitElement {
3666
3729
  id="${fieldId}"
3667
3730
  name="${fieldName}"
3668
3731
  class="${cssClass}"
3669
- .value="${effectiveValue || ""}"
3732
+ .value="${effectiveValue ?? ""}"
3670
3733
  ?disabled="${effectiveDisabled || this.field.disabled}"
3671
3734
  @change="${this._handleInput}"
3672
3735
  @focus="${this._handleFocus}"
@@ -3712,13 +3775,15 @@ let JupiterFormField = class extends LitElement {
3712
3775
  const step = typeConfig.step !== void 0 ? typeConfig.step : isNumericType(effectiveFieldType) ? "any" : void 0;
3713
3776
  const min = typeConfig.min;
3714
3777
  const max = typeConfig.max;
3778
+ const renderedInputValue = this._isNumericField() && this._numericDraftValue !== null ? this._numericDraftValue : effectiveValue ?? "";
3715
3779
  return html`
3716
3780
  <input
3717
3781
  id="${fieldId}"
3718
3782
  name="${fieldName}"
3719
3783
  type="${inputType}"
3784
+ inputmode="${typeConfig.inputMode || ""}"
3720
3785
  class="${cssClass}"
3721
- .value="${effectiveValue || ""}"
3786
+ .value="${renderedInputValue}"
3722
3787
  ?disabled="${effectiveDisabled || this.field.disabled}"
3723
3788
  placeholder="${typeConfig.placeholder || this.field.placeholder || ""}"
3724
3789
  step="${step !== void 0 ? step : ""}"
@@ -3737,7 +3802,7 @@ let JupiterFormField = class extends LitElement {
3737
3802
  case "decimal":
3738
3803
  case "currency":
3739
3804
  case "percentage":
3740
- return "number";
3805
+ return "text";
3741
3806
  case "date":
3742
3807
  return "date";
3743
3808
  case "datetime":
@@ -4567,6 +4632,9 @@ __decorateClass$6([
4567
4632
  __decorateClass$6([
4568
4633
  r()
4569
4634
  ], JupiterFormField.prototype, "_availableUnits", 2);
4635
+ __decorateClass$6([
4636
+ r()
4637
+ ], JupiterFormField.prototype, "_numericDraftValue", 2);
4570
4638
  JupiterFormField = __decorateClass$6([
4571
4639
  t$1("jupiter-form-field")
4572
4640
  ], JupiterFormField);
@@ -5020,25 +5088,30 @@ JupiterConceptTree.styles = css`
5020
5088
 
5021
5089
  .concept-info-btn {
5022
5090
  flex-shrink: 0;
5023
- width: 18px;
5024
- height: 18px;
5091
+ width: 22px;
5092
+ height: 22px;
5025
5093
  border-radius: 50%;
5026
- border: 1px solid transparent;
5027
- background: transparent;
5028
- color: var(--jupiter-text-secondary, #888);
5029
- font-size: 12px;
5094
+ border: 1px solid var(--jupiter-border-color, #cfd8dc);
5095
+ background: var(--jupiter-card-background, #fff);
5096
+ color: var(--jupiter-primary-color, #1976d2);
5097
+ font-size: 13px;
5098
+ font-weight: 700;
5030
5099
  cursor: pointer;
5031
5100
  display: flex;
5032
5101
  align-items: center;
5033
5102
  justify-content: center;
5034
5103
  opacity: 0;
5035
- transition: opacity 0.15s, background 0.15s, color 0.15s;
5104
+ transition: opacity 0.15s, background 0.15s, color 0.15s, border-color 0.15s, box-shadow 0.15s;
5036
5105
  padding: 0;
5037
5106
  margin-left: 4px;
5038
5107
  line-height: 1;
5108
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
5109
+ pointer-events: auto;
5039
5110
  }
5040
5111
 
5041
- .concept-content:hover .concept-info-btn {
5112
+ .concept-content:hover .concept-info-btn,
5113
+ .concept-info-btn:hover,
5114
+ .concept-info-btn:focus-visible {
5042
5115
  opacity: 1;
5043
5116
  }
5044
5117
 
@@ -5046,6 +5119,14 @@ JupiterConceptTree.styles = css`
5046
5119
  background: var(--jupiter-primary-color, #1976d2);
5047
5120
  color: #fff;
5048
5121
  border-color: var(--jupiter-primary-color, #1976d2);
5122
+ box-shadow: 0 2px 6px rgba(25, 118, 210, 0.25);
5123
+ }
5124
+
5125
+ .concept-info-btn:focus-visible {
5126
+ outline: none;
5127
+ border-color: var(--jupiter-primary-color, #1976d2);
5128
+ box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.25);
5129
+ opacity: 1;
5049
5130
  }
5050
5131
 
5051
5132
  `;
@@ -5439,7 +5520,7 @@ JupiterAddColumnDialog.styles = css`
5439
5520
  width: 100%;
5440
5521
  height: 100%;
5441
5522
  background: rgba(0, 0, 0, 0.5);
5442
- z-index: 1000;
5523
+ z-index: 1100;
5443
5524
  display: flex;
5444
5525
  align-items: center;
5445
5526
  justify-content: center;
@@ -5493,7 +5574,7 @@ JupiterAddColumnDialog.styles = css`
5493
5574
  margin-bottom: 24px;
5494
5575
  flex: 1;
5495
5576
  overflow-y: auto;
5496
- max-height: calc(90vh - 160px);
5577
+ min-height: 0;
5497
5578
  }
5498
5579
 
5499
5580
  .date-wrapper {
@@ -6642,6 +6723,7 @@ JupiterFormSection.styles = css`
6642
6723
  border-radius: 3px;
6643
6724
  font-size: 12px;
6644
6725
  background: var(--jupiter-input-background, #fff);
6726
+ color:#000;
6645
6727
  }
6646
6728
 
6647
6729
  .typed-member-header-field:focus {
@@ -7185,21 +7267,78 @@ let JupiterFilterRolesDialog = class extends LitElement {
7185
7267
  this._tempPeriodPreferences = newPreferences;
7186
7268
  this.requestUpdate();
7187
7269
  }
7270
+ _enforceSingleMemberSelectionsForRole(roleId, preferences) {
7271
+ const dimensions = this._getDimensionsForRole(roleId);
7272
+ if (dimensions.length === 0) {
7273
+ return preferences;
7274
+ }
7275
+ const nextPreferences = { ...preferences };
7276
+ const rolePreferences = nextPreferences[roleId] ? { ...nextPreferences[roleId] } : {
7277
+ showDuration: true,
7278
+ showInstant: true,
7279
+ showPreviousYear: false,
7280
+ dimensionSelections: []
7281
+ };
7282
+ const selections = rolePreferences.dimensionSelections ? [...rolePreferences.dimensionSelections] : [];
7283
+ dimensions.forEach((dimension) => {
7284
+ var _a, _b;
7285
+ if (!this._isSingleMemberDimension(dimension)) {
7286
+ return;
7287
+ }
7288
+ const allMembers = this._getAllDimensionMembers(dimension.members);
7289
+ if (allMembers.length !== 1) {
7290
+ return;
7291
+ }
7292
+ const onlyMemberId = allMembers[0].id;
7293
+ const dimensionLabel = ((_b = (_a = dimension.labels) == null ? void 0 : _a.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _b.label) || dimension.conceptName || dimension.id;
7294
+ const selectionIndex = selections.findIndex((ds) => ds.dimensionId === dimension.id);
7295
+ if (selectionIndex === -1) {
7296
+ selections.push({
7297
+ dimensionId: dimension.id,
7298
+ dimensionLabel,
7299
+ selectedMemberIds: [onlyMemberId]
7300
+ });
7301
+ return;
7302
+ }
7303
+ selections[selectionIndex] = {
7304
+ ...selections[selectionIndex],
7305
+ dimensionLabel,
7306
+ selectedMemberIds: [onlyMemberId]
7307
+ };
7308
+ });
7309
+ rolePreferences.dimensionSelections = selections;
7310
+ nextPreferences[roleId] = rolePreferences;
7311
+ return nextPreferences;
7312
+ }
7313
+ _enforceSingleMemberSelectionsForSelectedRoles(preferences, selectedRoles = this._tempSelectedRoles) {
7314
+ let nextPreferences = { ...preferences };
7315
+ for (const roleId of selectedRoles) {
7316
+ nextPreferences = this._enforceSingleMemberSelectionsForRole(roleId, nextPreferences);
7317
+ }
7318
+ return nextPreferences;
7319
+ }
7188
7320
  _handleCheckboxChange(event, roleId) {
7189
7321
  const checkbox = event.target;
7190
7322
  const newSelection = new Set(this._tempSelectedRoles);
7323
+ let newPreferences = { ...this._tempPeriodPreferences };
7191
7324
  if (checkbox.checked) {
7192
7325
  newSelection.add(roleId);
7326
+ newPreferences = this._enforceSingleMemberSelectionsForRole(roleId, newPreferences);
7193
7327
  } else {
7194
7328
  newSelection.delete(roleId);
7195
7329
  }
7196
7330
  this._tempSelectedRoles = newSelection;
7331
+ this._tempPeriodPreferences = newPreferences;
7197
7332
  this.requestUpdate();
7198
7333
  }
7199
7334
  _selectAll() {
7200
7335
  const newSelection = new Set(this._tempSelectedRoles);
7201
7336
  this._filteredRoles.forEach((role) => newSelection.add(role.id));
7202
7337
  this._tempSelectedRoles = newSelection;
7338
+ this._tempPeriodPreferences = this._enforceSingleMemberSelectionsForSelectedRoles(
7339
+ this._tempPeriodPreferences,
7340
+ newSelection
7341
+ );
7203
7342
  this.requestUpdate();
7204
7343
  }
7205
7344
  _selectNone() {
@@ -7209,7 +7348,12 @@ let JupiterFilterRolesDialog = class extends LitElement {
7209
7348
  this.requestUpdate();
7210
7349
  }
7211
7350
  _selectAllGlobal() {
7212
- this._tempSelectedRoles = new Set(this.availableRoles.map((role) => role.id));
7351
+ const newSelection = new Set(this.availableRoles.map((role) => role.id));
7352
+ this._tempSelectedRoles = newSelection;
7353
+ this._tempPeriodPreferences = this._enforceSingleMemberSelectionsForSelectedRoles(
7354
+ this._tempPeriodPreferences,
7355
+ newSelection
7356
+ );
7213
7357
  this.requestUpdate();
7214
7358
  }
7215
7359
  _selectNoneGlobal() {
@@ -7218,6 +7362,10 @@ let JupiterFilterRolesDialog = class extends LitElement {
7218
7362
  }
7219
7363
  _resetToOriginal() {
7220
7364
  this._tempSelectedRoles = new Set(this.selectedRoleIds);
7365
+ this._tempPeriodPreferences = this._enforceSingleMemberSelectionsForSelectedRoles(
7366
+ this._tempPeriodPreferences,
7367
+ this._tempSelectedRoles
7368
+ );
7221
7369
  this.requestUpdate();
7222
7370
  }
7223
7371
  _handleCancel() {
@@ -7227,6 +7375,11 @@ let JupiterFilterRolesDialog = class extends LitElement {
7227
7375
  }));
7228
7376
  }
7229
7377
  _handleApply() {
7378
+ const normalizedPreferences = this._enforceSingleMemberSelectionsForSelectedRoles(
7379
+ this._tempPeriodPreferences,
7380
+ this._tempSelectedRoles
7381
+ );
7382
+ this._tempPeriodPreferences = normalizedPreferences;
7230
7383
  const orderedSelected = this._chosenRoleOrder.filter((id) => this._tempSelectedRoles.has(id));
7231
7384
  const notInOrder = Array.from(this._tempSelectedRoles).filter((id) => !this._chosenRoleOrder.includes(id));
7232
7385
  this._chosenRoleOrder = [...orderedSelected, ...notInOrder];
@@ -7241,11 +7394,11 @@ let JupiterFilterRolesDialog = class extends LitElement {
7241
7394
  });
7242
7395
  console.log("✅ Apply Filter - Enhanced structure being emitted:", orderedRolesWithMetadata);
7243
7396
  console.log("📋 Order array:", this._chosenRoleOrder);
7244
- console.log("📊 Dimension preferences being emitted:", this._tempPeriodPreferences);
7397
+ console.log("📊 Dimension preferences being emitted:", normalizedPreferences);
7245
7398
  this.dispatchEvent(new CustomEvent("roles-filter-apply", {
7246
7399
  detail: {
7247
7400
  selectedRoleIds: orderedRolesWithMetadata,
7248
- periodPreferences: this._tempPeriodPreferences
7401
+ periodPreferences: normalizedPreferences
7249
7402
  },
7250
7403
  bubbles: true
7251
7404
  }));
@@ -7351,9 +7504,9 @@ let JupiterFilterRolesDialog = class extends LitElement {
7351
7504
  (ds) => ds.dimensionId === dimensionId
7352
7505
  );
7353
7506
  if (!dimensionSelection) {
7354
- const dimensions = this._getDimensionsForRole(roleId);
7355
- const dimension = dimensions.find((d2) => d2.id === dimensionId);
7356
- const dimensionLabel = ((_b = (_a = dimension == null ? void 0 : dimension.labels) == null ? void 0 : _a.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _b.label) || dimensionId;
7507
+ const dimensions2 = this._getDimensionsForRole(roleId);
7508
+ const dimension2 = dimensions2.find((d2) => d2.id === dimensionId);
7509
+ const dimensionLabel = ((_b = (_a = dimension2 == null ? void 0 : dimension2.labels) == null ? void 0 : _a.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _b.label) || dimensionId;
7357
7510
  dimensionSelection = {
7358
7511
  dimensionId,
7359
7512
  dimensionLabel,
@@ -7370,6 +7523,15 @@ let JupiterFilterRolesDialog = class extends LitElement {
7370
7523
  (id) => id !== memberId
7371
7524
  );
7372
7525
  }
7526
+ const dimensions = this._getDimensionsForRole(roleId);
7527
+ const dimension = dimensions.find((d2) => d2.id === dimensionId);
7528
+ if (dimension && this._tempSelectedRoles.has(roleId) && this._isSingleMemberDimension(dimension)) {
7529
+ const allMembers = this._getAllDimensionMembers(dimension.members);
7530
+ if (allMembers.length === 1) {
7531
+ dimensionSelection.selectedMemberIds = [allMembers[0].id];
7532
+ checkbox.checked = true;
7533
+ }
7534
+ }
7373
7535
  this._tempPeriodPreferences = newPreferences;
7374
7536
  console.log("📊 Updated dimension selections:", newPreferences[roleId].dimensionSelections);
7375
7537
  this.requestUpdate();
@@ -7483,6 +7645,10 @@ let JupiterFilterRolesDialog = class extends LitElement {
7483
7645
  const newSelection = new Set(this._tempSelectedRoles);
7484
7646
  newSelection.add(this._selectedAvailableRole);
7485
7647
  this._tempSelectedRoles = newSelection;
7648
+ this._tempPeriodPreferences = this._enforceSingleMemberSelectionsForRole(
7649
+ this._selectedAvailableRole,
7650
+ this._tempPeriodPreferences
7651
+ );
7486
7652
  if (!this._chosenRoleOrder.includes(this._selectedAvailableRole)) {
7487
7653
  this._chosenRoleOrder = [...this._chosenRoleOrder, this._selectedAvailableRole];
7488
7654
  }
@@ -7508,6 +7674,10 @@ let JupiterFilterRolesDialog = class extends LitElement {
7508
7674
  }
7509
7675
  });
7510
7676
  this._tempSelectedRoles = newSelection;
7677
+ this._tempPeriodPreferences = this._enforceSingleMemberSelectionsForSelectedRoles(
7678
+ this._tempPeriodPreferences,
7679
+ newSelection
7680
+ );
7511
7681
  this._selectedAvailableRole = null;
7512
7682
  this.requestUpdate();
7513
7683
  }
@@ -7878,7 +8048,6 @@ let JupiterFilterRolesDialog = class extends LitElement {
7878
8048
  return html``;
7879
8049
  }
7880
8050
  const dimensionLabel = ((_b = (_a2 = dimension.labels) == null ? void 0 : _a2.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _b.label) || dimension.conceptName;
7881
- const isSingleMember = this._isSingleMemberDimension(dimension);
7882
8051
  return html`
7883
8052
  <div class="dimension-group">
7884
8053
  <div class="dimension-label">${dimensionLabel}</div>
@@ -7893,7 +8062,6 @@ let JupiterFilterRolesDialog = class extends LitElement {
7893
8062
  type="checkbox"
7894
8063
  class="member-checkbox"
7895
8064
  .checked="${isChecked}"
7896
- ?disabled="${isSingleMember}"
7897
8065
  @change="${(e2) => this._handleDimensionMemberChange(e2, role.id, dimension.id, member.id)}"
7898
8066
  />
7899
8067
  <span class="member-checkbox-label">${memberLabel}</span>
@@ -7901,22 +8069,20 @@ let JupiterFilterRolesDialog = class extends LitElement {
7901
8069
  `;
7902
8070
  })}
7903
8071
  </div>
7904
- ${!isSingleMember ? html`
7905
- <div class="member-select-controls">
7906
- <button
7907
- class="member-select-btn"
7908
- @click="${() => this._selectAllDimensionMembers(role.id, dimension.id)}"
7909
- >
7910
- ${I18n.t("filter.selectAllMembers")}
7911
- </button>
7912
- <button
7913
- class="member-select-btn"
7914
- @click="${() => this._deselectAllDimensionMembers(role.id, dimension.id)}"
7915
- >
7916
- ${I18n.t("filter.clearMembers")}
7917
- </button>
7918
- </div>
7919
- ` : ""}
8072
+ <div class="member-select-controls">
8073
+ <button
8074
+ class="member-select-btn"
8075
+ @click="${() => this._selectAllDimensionMembers(role.id, dimension.id)}"
8076
+ >
8077
+ ${I18n.t("filter.selectAllMembers")}
8078
+ </button>
8079
+ <button
8080
+ class="member-select-btn"
8081
+ @click="${() => this._deselectAllDimensionMembers(role.id, dimension.id)}"
8082
+ >
8083
+ ${I18n.t("filter.clearMembers")}
8084
+ </button>
8085
+ </div>
7920
8086
  </div>
7921
8087
  `;
7922
8088
  })}
@@ -9968,25 +10134,26 @@ let JupiterDynamicForm = class extends LitElement {
9968
10134
  return [];
9969
10135
  }
9970
10136
  const availableDimensions = [];
10137
+ const lang = this.language || "en";
10138
+ const pickLabel = (labels, fallback) => {
10139
+ var _a2;
10140
+ return ((_a2 = (labels == null ? void 0 : labels.find((l2) => l2.lang === lang && l2.role === "http://www.xbrl.org/2003/role/label")) || (labels == null ? void 0 : labels.find((l2) => l2.lang === "en" && l2.role === "http://www.xbrl.org/2003/role/label")) || (labels == null ? void 0 : labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label"))) == null ? void 0 : _a2.label) || fallback;
10141
+ };
9971
10142
  hypercubeRole.items.forEach((item) => {
9972
10143
  if (item.dimensions && item.dimensions.length > 0) {
9973
10144
  item.dimensions.forEach((dimension) => {
9974
- var _a2;
9975
10145
  if (!availableDimensions.find((d2) => d2.id === dimension.id)) {
9976
- const axisLabel = ((_a2 = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _a2.label) || dimension.conceptName;
10146
+ const axisLabel = pickLabel(dimension.labels, dimension.conceptName);
9977
10147
  const availableDimension = {
9978
10148
  id: dimension.id,
9979
10149
  conceptName: dimension.conceptName,
9980
10150
  axisLabel
9981
10151
  };
9982
10152
  if (dimension.members && dimension.members.length > 0) {
9983
- availableDimension.members = dimension.members.map((member) => {
9984
- var _a3, _b2;
9985
- return {
9986
- id: member.id,
9987
- label: ((_b2 = (_a3 = member.labels) == null ? void 0 : _a3.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _b2.label) || member.conceptName || member.id
9988
- };
9989
- });
10153
+ availableDimension.members = dimension.members.map((member) => ({
10154
+ id: member.id,
10155
+ label: pickLabel(member.labels, member.conceptName || member.id)
10156
+ }));
9990
10157
  }
9991
10158
  if (dimension.typedMember) {
9992
10159
  availableDimension.typedMember = {
@@ -10915,7 +11082,7 @@ let JupiterDynamicForm = class extends LitElement {
10915
11082
  if (concept.abstract)
10916
11083
  return;
10917
11084
  const isCustomColumn = column2.id.startsWith("col-");
10918
- const isDimensionColumn = column2.id.startsWith("duration_") || column2.id.startsWith("instant_");
11085
+ const isDimensionColumn = column2.id.startsWith("duration_") || column2.id.startsWith("instant_") || column2.id.startsWith("typed-");
10919
11086
  const isMixedSection = section2.showPeriodControl === true;
10920
11087
  const shouldSkipPeriodCheck = !columnPeriodType || column2.id === "duration" || column2.id === "default" || isCustomColumn && isMixedSection || isDimensionColumn;
10921
11088
  if (!shouldSkipPeriodCheck && conceptPeriodType && columnPeriodType) {
@@ -12950,35 +13117,35 @@ JupiterDynamicForm.styles = css`
12950
13117
  }
12951
13118
 
12952
13119
  .side-panel-role-item.has-errors {
12953
- border-left: 2px solid var(--jupiter-error-color, #d32f2f);
13120
+ border-left: 4px solid var(--jupiter-error-color, #d32f2f);
12954
13121
  }
12955
13122
 
12956
13123
  .side-panel-role-item.has-errors.active {
12957
- border-left: 2px solid var(--jupiter-error-color, #d32f2f);
13124
+ border-left: 4px solid var(--jupiter-error-color, #d32f2f);
12958
13125
  }
12959
13126
 
12960
13127
  .side-panel-role-item.has-no-data {
12961
- border-left: 2px solid var(--jupiter-untouched-color, #757575);
13128
+ border-left: 4px solid var(--jupiter-untouched-color, #757575);
12962
13129
  }
12963
13130
 
12964
13131
  .side-panel-role-item.has-no-data.active {
12965
- border-left: 2px solid var(--jupiter-untouched-color, #757575);
13132
+ border-left: 4px solid var(--jupiter-untouched-color, #757575);
12966
13133
  }
12967
13134
 
12968
13135
  .side-panel-role-item.has-empty-fields {
12969
- border-left: 2px solid var(--jupiter-warning-color, #ff9800);
13136
+ border-left: 4px solid var(--jupiter-warning-color, #ff9800);
12970
13137
  }
12971
13138
 
12972
13139
  .side-panel-role-item.has-empty-fields.active {
12973
- border-left: 2px solid var(--jupiter-warning-color, #ff9800);
13140
+ border-left: 4px solid var(--jupiter-warning-color, #ff9800);
12974
13141
  }
12975
13142
 
12976
13143
  .side-panel-role-item.has-complete-data {
12977
- border-left: 2px solid var(--jupiter-success-color, #4caf50);
13144
+ border-left: 4px solid var(--jupiter-success-color, #4caf50);
12978
13145
  }
12979
13146
 
12980
13147
  .side-panel-role-item.has-complete-data.active {
12981
- border-left: 2px solid var(--jupiter-success-color, #4caf50);
13148
+ border-left: 4px solid var(--jupiter-success-color, #4caf50);
12982
13149
  }
12983
13150
 
12984
13151
  .role-completion-row {