@carbon/vue 3.0.29 → 3.0.30

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.
@@ -1 +1 @@
1
- #invalid-message-placeholder{display:block;height:16px}.inputWrapper[data-v-1da605fd]{width:8.96875rem}.label[data-v-1da605fd]{width:4.6875rem;height:.875rem;margin-bottom:.5rem}.input[data-v-1da605fd]{height:2.5rem;margin-bottom:0}
1
+ #invalid-message-placeholder{display:block;height:16px}.inputWrapper[data-v-1da605fd]{width:8.96875rem}.label[data-v-1da605fd]{width:4.6875rem;height:.875rem;margin-bottom:.5rem}.input[data-v-1da605fd]{height:2.5rem;margin-bottom:0}.bx--list-box .bx--list-box__menu{overflow-y:hidden!important}.bx--list-box--expanded .bx--list-box__menu.cv-dropdown__menu--transition-done{overflow-y:auto!important}
@@ -9322,7 +9322,7 @@ const __exports__ = /*#__PURE__*/(0,exportHelper/* default */.A)(CvDatePickerSke
9322
9322
 
9323
9323
  /***/ }),
9324
9324
 
9325
- /***/ 306:
9325
+ /***/ 4230:
9326
9326
  /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9327
9327
 
9328
9328
  "use strict";
@@ -9518,6 +9518,7 @@ var _hoisted_7 = ["aria-disabled"];
9518
9518
  var itemsList = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.ref)([]);
9519
9519
  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.provide)('dropdown-items', itemsList);
9520
9520
  var open = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.ref)(false);
9521
+ var transitionDone = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.ref)(false);
9521
9522
  var data = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.reactive)({
9522
9523
  isHelper: false,
9523
9524
  isInvalid: undefined,
@@ -9549,6 +9550,15 @@ var _hoisted_7 = ["aria-disabled"];
9549
9550
  });
9550
9551
  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.watch)(open, function () {
9551
9552
  focusItem.value = '';
9553
+ if (open.value) {
9554
+ // Wait for the transition to complete before allowing overflow
9555
+ transitionDone.value = false;
9556
+ setTimeout(function () {
9557
+ transitionDone.value = true;
9558
+ }, 200); // Increase delay to ensure animation completes
9559
+ } else {
9560
+ transitionDone.value = false;
9561
+ }
9552
9562
  });
9553
9563
  var ariaLabeledBy = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.computed)(function () {
9554
9564
  if (props.label) {
@@ -9733,7 +9743,9 @@ var _hoisted_7 = ["aria-disabled"];
9733
9743
  ref: dropList,
9734
9744
  "aria-hidden": !open.value ? 'true' : 'false',
9735
9745
  "aria-labelledby": "".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(uid), "-label"),
9736
- class: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeClass)("".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--list-box__menu")),
9746
+ class: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeClass)(["".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--list-box__menu"), {
9747
+ 'cv-dropdown__menu--transition-done': transitionDone.value
9748
+ }]),
9737
9749
  role: "menu",
9738
9750
  tabindex: "-1"
9739
9751
  }, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.renderSlot)(_ctx.$slots, "default", {}, function () {
@@ -9774,10 +9786,17 @@ var _hoisted_7 = ["aria-disabled"];
9774
9786
  });
9775
9787
  ;// ./src/components/CvDropdown/CvDropdown.vue?vue&type=script&setup=true&lang=js
9776
9788
 
9789
+ ;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-64.use[0]!./node_modules/@vue/cli-service/node_modules/css-loader/dist/cjs.js??clonedRuleSet-64.use[1]!./node_modules/@vue/cli-service/node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/@vue/cli-service/node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-64.use[2]!./node_modules/sass-loader/dist/cjs.js??clonedRuleSet-64.use[3]!./node_modules/@vue/cli-service/node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/CvDropdown/CvDropdown.vue?vue&type=style&index=0&id=21e6324c&lang=scss
9790
+ // extracted by mini-css-extract-plugin
9791
+
9792
+ ;// ./src/components/CvDropdown/CvDropdown.vue?vue&type=style&index=0&id=21e6324c&lang=scss
9793
+
9777
9794
  ;// ./src/components/CvDropdown/CvDropdown.vue
9778
9795
 
9779
9796
 
9780
9797
 
9798
+ ;
9799
+
9781
9800
  const __exports__ = CvDropdownvue_type_script_setup_true_lang_js;
9782
9801
 
9783
9802
  /* harmony default export */ var CvDropdown = (__exports__);
@@ -13959,7 +13978,7 @@ var _hoisted_3 = ["id", "aria-labelledby"];
13959
13978
  var tryOn = _step.value;
13960
13979
  if (
13961
13980
  // don't focus on before after or something that can't be tabbed to
13962
- !(tryOn.classList.contains('cv-overflow-menu__before-content') || tryOn.classList.contains('cv-overflow-menu__after-content') || tryOn.tabindex < 0)) {
13981
+ !(tryOn.classList.contains('cv-overflow-menu__before-content') || tryOn.classList.contains('cv-overflow-menu__after-content') || tryOn.tabindex < 0 || tryOn.disabled)) {
13963
13982
  focusOn = tryOn;
13964
13983
  break;
13965
13984
  }
@@ -17078,7 +17097,7 @@ const __exports__ = CvTabvue_type_script_setup_true_lang_js;
17078
17097
 
17079
17098
  /***/ }),
17080
17099
 
17081
- /***/ 4240:
17100
+ /***/ 7558:
17082
17101
  /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
17083
17102
 
17084
17103
  "use strict";
@@ -17092,6 +17111,40 @@ __webpack_require__.d(__webpack_exports__, {
17092
17111
 
17093
17112
  // EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/defineProperty.js + 2 modules
17094
17113
  var defineProperty = __webpack_require__(9635);
17114
+ // EXTERNAL MODULE: ./node_modules/core-js/modules/es.symbol.js
17115
+ var es_symbol = __webpack_require__(3534);
17116
+ ;// ./node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js
17117
+ function _objectWithoutPropertiesLoose(r, e) {
17118
+ if (null == r) return {};
17119
+ var t = {};
17120
+ for (var n in r) {
17121
+ if ({}.hasOwnProperty.call(r, n)) {
17122
+ if (-1 !== e.indexOf(n)) continue;
17123
+ t[n] = r[n];
17124
+ }
17125
+ }
17126
+ return t;
17127
+ }
17128
+
17129
+ ;// ./node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js
17130
+
17131
+
17132
+ function _objectWithoutProperties(e, t) {
17133
+ if (null == e) return {};
17134
+ var o,
17135
+ r,
17136
+ i = _objectWithoutPropertiesLoose(e, t);
17137
+ if (Object.getOwnPropertySymbols) {
17138
+ var n = Object.getOwnPropertySymbols(e);
17139
+ for (r = 0; r < n.length; r++) {
17140
+ o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
17141
+ }
17142
+ }
17143
+ return i;
17144
+ }
17145
+
17146
+ // EXTERNAL MODULE: ./node_modules/core-js/modules/es.object.assign.js
17147
+ var es_object_assign = __webpack_require__(9218);
17095
17148
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array.iterator.js
17096
17149
  var es_array_iterator = __webpack_require__(8665);
17097
17150
  // EXTERNAL MODULE: ./node_modules/core-js/modules/es.object.to-string.js
@@ -17147,6 +17200,9 @@ var _16 = __webpack_require__(238);
17147
17200
  ;// ./node_modules/thread-loader/dist/cjs.js!./node_modules/@vue/cli-plugin-babel/node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!./node_modules/@vue/cli-service/node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/CvTabs/CvTabs.vue?vue&type=script&setup=true&lang=js
17148
17201
 
17149
17202
 
17203
+ var _excluded = ["aria-label"];
17204
+
17205
+
17150
17206
 
17151
17207
 
17152
17208
 
@@ -17161,16 +17217,20 @@ var _hoisted_1 = {
17161
17217
  "width": "100%"
17162
17218
  }
17163
17219
  };
17164
- var _hoisted_2 = ["onKeydown"];
17165
- var _hoisted_3 = ["id", "aria-controls", "aria-disabled", "aria-selected", "tabindex", "onClick"];
17166
- var _hoisted_4 = {
17220
+ var _hoisted_2 = ["aria-label", "onKeydown"];
17221
+ var _hoisted_3 = ["aria-label", "tabIndex"];
17222
+ var _hoisted_4 = ["id", "aria-controls", "aria-disabled", "aria-selected", "tabindex", "onClick"];
17223
+ var _hoisted_5 = ["aria-label", "tabIndex"];
17224
+ var _hoisted_6 = {
17167
17225
  class: "cv-tabs__panels"
17168
17226
  };
17169
17227
 
17170
17228
 
17171
17229
 
17172
17230
  var OVERFLOW_BUTTON_OFFSET = 40;
17173
- /* harmony default export */ var CvTabsvue_type_script_setup_true_lang_js = ({
17231
+ /* harmony default export */ var CvTabsvue_type_script_setup_true_lang_js = (/*@__PURE__*/Object.assign({
17232
+ inheritAttrs: false
17233
+ }, {
17174
17234
  __name: 'CvTabs',
17175
17235
  props: {
17176
17236
  /**
@@ -17214,6 +17274,12 @@ var OVERFLOW_BUTTON_OFFSET = 40;
17214
17274
  var __emit = _ref.emit;
17215
17275
  var props = __props;
17216
17276
  var emit = __emit;
17277
+ var attrs = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.useAttrs)();
17278
+ var attrsWithoutAriaLabel = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.computed)(function () {
17279
+ var _ = attrs['aria-label'],
17280
+ rest = _objectWithoutProperties(attrs, _excluded);
17281
+ return rest;
17282
+ });
17217
17283
  var selectedId = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.ref)('');
17218
17284
  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.provide)('tab-selected', selectedId);
17219
17285
  /**
@@ -17469,16 +17535,16 @@ var OVERFLOW_BUTTON_OFFSET = 40;
17469
17535
  return (0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", _hoisted_1, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", (0,external_commonjs_vue_commonjs2_vue_root_Vue_.mergeProps)({
17470
17536
  "data-tabs": "",
17471
17537
  class: ["cv-tab ".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tabs--scrollable"), (_ref4 = {}, (0,defineProperty/* default */.A)(_ref4, "".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tabs--container"), __props.container), (0,defineProperty/* default */.A)(_ref4, "".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tabs--scrollable--container"), __props.container), _ref4)],
17472
- role: "navigation"
17473
- }, _ctx.$attrs, {
17538
+ role: "navigation",
17539
+ "aria-label": (0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(attrs)['aria-label'] || 'Tabs'
17540
+ }, attrsWithoutAriaLabel.value, {
17474
17541
  onKeydown: [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.withKeys)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.withModifiers)(onRight, ["prevent", "stop"]), ["right"]), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withKeys)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.withModifiers)(onLeft, ["prevent", "stop"]), ["left"])]
17475
17542
  }), [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("button", {
17476
17543
  ref_key: "elLeftOverflow",
17477
17544
  ref: elLeftOverflow,
17478
- "aria-hidden": "true",
17479
- "aria-label": "scroll left",
17545
+ "aria-label": leftOverflowNavButtonHidden.value ? undefined : 'Scroll tabs left',
17480
17546
  class: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeClass)([(_ref5 = {}, (0,defineProperty/* default */.A)(_ref5, "".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tab--overflow-nav-button"), horizontalOverflow.value), (0,defineProperty/* default */.A)(_ref5, "".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tab--overflow-nav-button--hidden"), leftOverflowNavButtonHidden.value), _ref5)]),
17481
- tabIndex: "-1",
17547
+ tabIndex: leftOverflowNavButtonHidden.value ? -1 : 0,
17482
17548
  type: "button",
17483
17549
  onClick: _cache[0] || (_cache[0] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withModifiers)(function (e) {
17484
17550
  return onOverflowClick(e, {
@@ -17491,7 +17557,7 @@ var OVERFLOW_BUTTON_OFFSET = 40;
17491
17557
  });
17492
17558
  }, ["stop", "prevent"])),
17493
17559
  onMouseup: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withModifiers)(onOverflowMouseUp, ["stop", "prevent"])
17494
- }, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.createVNode)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(ChevronLeft16))], 34), !leftOverflowNavButtonHidden.value ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", {
17560
+ }, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.createVNode)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(ChevronLeft16))], 42, _hoisted_3), !leftOverflowNavButtonHidden.value ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", {
17495
17561
  key: 0,
17496
17562
  class: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeClass)("".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tabs__overflow-indicator--left"))
17497
17563
  }, null, 2)) : (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createCommentVNode)("", true), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("ul", {
@@ -17524,17 +17590,16 @@ var OVERFLOW_BUTTON_OFFSET = 40;
17524
17590
  ref_for: true
17525
17591
  }, tab), function () {
17526
17592
  return [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.createTextVNode)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.toDisplayString)(tab.label), 1)];
17527
- })], 10, _hoisted_3)], 2);
17593
+ })], 10, _hoisted_4)], 2);
17528
17594
  }), 128))], 2), !rightOverflowNavButtonHidden.value ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", {
17529
17595
  key: 1,
17530
17596
  class: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeClass)("".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tabs__overflow-indicator--right"))
17531
17597
  }, null, 2)) : (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createCommentVNode)("", true), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("button", {
17532
17598
  ref_key: "elRightOverflow",
17533
17599
  ref: elRightOverflow,
17534
- "aria-hidden": "true",
17535
- "aria-label": "scroll right",
17600
+ "aria-label": rightOverflowNavButtonHidden.value ? undefined : 'Scroll tabs right',
17536
17601
  class: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeClass)([(_ref7 = {}, (0,defineProperty/* default */.A)(_ref7, "".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tab--overflow-nav-button"), horizontalOverflow.value), (0,defineProperty/* default */.A)(_ref7, "".concat((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(settings/* carbonPrefix */.s), "--tab--overflow-nav-button--hidden"), rightOverflowNavButtonHidden.value), _ref7)]),
17537
- tabIndex: "-1",
17602
+ tabIndex: rightOverflowNavButtonHidden.value ? -1 : 0,
17538
17603
  type: "button",
17539
17604
  onClick: _cache[2] || (_cache[2] = function (e) {
17540
17605
  return onOverflowClick(e, {
@@ -17547,10 +17612,10 @@ var OVERFLOW_BUTTON_OFFSET = 40;
17547
17612
  });
17548
17613
  }),
17549
17614
  onMouseup: onOverflowMouseUp
17550
- }, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.createVNode)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(_16/* default */.A))], 34)], 16, _hoisted_2), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_4, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.renderSlot)(_ctx.$slots, "default")])]);
17615
+ }, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.createVNode)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.unref)(_16/* default */.A))], 42, _hoisted_5)], 16, _hoisted_2), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_6, [(0,external_commonjs_vue_commonjs2_vue_root_Vue_.renderSlot)(_ctx.$slots, "default")])]);
17551
17616
  };
17552
17617
  }
17553
- });
17618
+ }));
17554
17619
  ;// ./src/components/CvTabs/CvTabs.vue?vue&type=script&setup=true&lang=js
17555
17620
 
17556
17621
  ;// ./src/components/CvTabs/CvTabs.vue
@@ -42367,7 +42432,7 @@ var map = {
42367
42432
  "./CvDataTable/CvDataTableSkeleton.vue": 2446,
42368
42433
  "./CvDatePicker/CvDatePicker.vue": 8285,
42369
42434
  "./CvDatePicker/CvDatePickerSkeleton.vue": 333,
42370
- "./CvDropdown/CvDropdown.vue": 306,
42435
+ "./CvDropdown/CvDropdown.vue": 4230,
42371
42436
  "./CvDropdown/CvDropdownItem.vue": 8073,
42372
42437
  "./CvDropdown/CvDropdownSkeleton.vue": 8728,
42373
42438
  "./CvFileUploader/CvFileUploader.vue": 9715,
@@ -42412,7 +42477,7 @@ var map = {
42412
42477
  "./CvStructuredList/CvStructuredListItemSelectable.vue": 8978,
42413
42478
  "./CvStructuredList/CvStructuredListItemStandard.vue": 9623,
42414
42479
  "./CvTabs/CvTab.vue": 9763,
42415
- "./CvTabs/CvTabs.vue": 4240,
42480
+ "./CvTabs/CvTabs.vue": 7558,
42416
42481
  "./CvTabs/CvTabsSkeleton.vue": 1413,
42417
42482
  "./CvTag/CvTag.vue": 8410,
42418
42483
  "./CvTag/CvTagSkeleton.vue": 2579,
@@ -43359,8 +43424,8 @@ var CvDataTableSkeleton = __webpack_require__(2446);
43359
43424
  var CvDatePicker = __webpack_require__(8285);
43360
43425
  // EXTERNAL MODULE: ./src/components/CvDatePicker/CvDatePickerSkeleton.vue + 4 modules
43361
43426
  var CvDatePickerSkeleton = __webpack_require__(333);
43362
- // EXTERNAL MODULE: ./src/components/CvDropdown/CvDropdown.vue + 2 modules
43363
- var CvDropdown = __webpack_require__(306);
43427
+ // EXTERNAL MODULE: ./src/components/CvDropdown/CvDropdown.vue + 4 modules
43428
+ var CvDropdown = __webpack_require__(4230);
43364
43429
  // EXTERNAL MODULE: ./src/components/CvDropdown/CvDropdownItem.vue + 2 modules
43365
43430
  var CvDropdownItem = __webpack_require__(8073);
43366
43431
  // EXTERNAL MODULE: ./src/components/CvDropdown/CvDropdownSkeleton.vue + 2 modules
@@ -43449,8 +43514,8 @@ var CvStructuredListItemSelectable = __webpack_require__(8978);
43449
43514
  var CvStructuredListItemStandard = __webpack_require__(9623);
43450
43515
  // EXTERNAL MODULE: ./src/components/CvTabs/CvTab.vue + 2 modules
43451
43516
  var CvTab = __webpack_require__(9763);
43452
- // EXTERNAL MODULE: ./src/components/CvTabs/CvTabs.vue + 3 modules
43453
- var CvTabs = __webpack_require__(4240);
43517
+ // EXTERNAL MODULE: ./src/components/CvTabs/CvTabs.vue + 5 modules
43518
+ var CvTabs = __webpack_require__(7558);
43454
43519
  // EXTERNAL MODULE: ./src/components/CvTabs/CvTabsSkeleton.vue + 2 modules
43455
43520
  var CvTabsSkeleton = __webpack_require__(1413);
43456
43521
  // EXTERNAL MODULE: ./src/components/CvTag/CvTag.vue + 4 modules