@patternfly/pfe-core 3.0.0 → 4.0.1

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.
Files changed (102) hide show
  1. package/controllers/activedescendant-controller.d.ts +99 -0
  2. package/controllers/activedescendant-controller.js +230 -0
  3. package/controllers/activedescendant-controller.js.map +1 -0
  4. package/controllers/at-focus-controller.d.ts +56 -0
  5. package/controllers/at-focus-controller.js +168 -0
  6. package/controllers/at-focus-controller.js.map +1 -0
  7. package/controllers/cascade-controller.d.ts +7 -2
  8. package/controllers/cascade-controller.js +6 -1
  9. package/controllers/cascade-controller.js.map +1 -1
  10. package/controllers/combobox-controller.d.ts +117 -0
  11. package/controllers/combobox-controller.js +611 -0
  12. package/controllers/combobox-controller.js.map +1 -0
  13. package/controllers/css-variable-controller.js +1 -1
  14. package/controllers/css-variable-controller.js.map +1 -1
  15. package/controllers/floating-dom-controller.d.ts +8 -1
  16. package/controllers/floating-dom-controller.js +12 -5
  17. package/controllers/floating-dom-controller.js.map +1 -1
  18. package/controllers/internals-controller.d.ts +26 -9
  19. package/controllers/internals-controller.js +45 -13
  20. package/controllers/internals-controller.js.map +1 -1
  21. package/controllers/light-dom-controller.js +2 -2
  22. package/controllers/light-dom-controller.js.map +1 -1
  23. package/controllers/listbox-controller.d.ts +118 -33
  24. package/controllers/listbox-controller.js +347 -154
  25. package/controllers/listbox-controller.js.map +1 -1
  26. package/controllers/logger.d.ts +13 -10
  27. package/controllers/logger.js +15 -11
  28. package/controllers/logger.js.map +1 -1
  29. package/controllers/overflow-controller.js +10 -6
  30. package/controllers/overflow-controller.js.map +1 -1
  31. package/controllers/perf-controller.js.map +1 -1
  32. package/controllers/property-observer-controller.d.ts +13 -16
  33. package/controllers/property-observer-controller.js +54 -25
  34. package/controllers/property-observer-controller.js.map +1 -1
  35. package/controllers/roving-tabindex-controller.d.ts +12 -61
  36. package/controllers/roving-tabindex-controller.js +57 -203
  37. package/controllers/roving-tabindex-controller.js.map +1 -1
  38. package/controllers/scroll-spy-controller.d.ts +4 -1
  39. package/controllers/scroll-spy-controller.js +9 -6
  40. package/controllers/scroll-spy-controller.js.map +1 -1
  41. package/controllers/slot-controller.d.ts +12 -16
  42. package/controllers/slot-controller.js +17 -20
  43. package/controllers/slot-controller.js.map +1 -1
  44. package/controllers/style-controller.js +3 -1
  45. package/controllers/style-controller.js.map +1 -1
  46. package/controllers/tabs-aria-controller.d.ts +2 -0
  47. package/controllers/tabs-aria-controller.js +2 -0
  48. package/controllers/tabs-aria-controller.js.map +1 -1
  49. package/controllers/test/combobox-controller.spec.d.ts +1 -0
  50. package/controllers/test/combobox-controller.spec.js +282 -0
  51. package/controllers/test/combobox-controller.spec.js.map +1 -0
  52. package/controllers/timestamp-controller.js +7 -2
  53. package/controllers/timestamp-controller.js.map +1 -1
  54. package/core.d.ts +0 -23
  55. package/core.js +1 -38
  56. package/core.js.map +1 -1
  57. package/custom-elements.json +3862 -1369
  58. package/decorators/bound.d.ts +3 -1
  59. package/decorators/bound.js +3 -1
  60. package/decorators/bound.js.map +1 -1
  61. package/decorators/cascades.d.ts +2 -1
  62. package/decorators/cascades.js +2 -1
  63. package/decorators/cascades.js.map +1 -1
  64. package/decorators/deprecation.d.ts +6 -5
  65. package/decorators/deprecation.js +6 -5
  66. package/decorators/deprecation.js.map +1 -1
  67. package/decorators/initializer.js.map +1 -1
  68. package/decorators/listen.d.ts +8 -0
  69. package/decorators/listen.js +22 -0
  70. package/decorators/listen.js.map +1 -0
  71. package/decorators/observed.d.ts +12 -16
  72. package/decorators/observed.js +39 -44
  73. package/decorators/observed.js.map +1 -1
  74. package/decorators/observes.d.ts +15 -0
  75. package/decorators/observes.js +30 -0
  76. package/decorators/observes.js.map +1 -0
  77. package/decorators/time.d.ts +1 -0
  78. package/decorators/time.js +6 -9
  79. package/decorators/time.js.map +1 -1
  80. package/decorators/trace.d.ts +4 -1
  81. package/decorators/trace.js +4 -1
  82. package/decorators/trace.js.map +1 -1
  83. package/decorators.d.ts +2 -0
  84. package/decorators.js +2 -0
  85. package/decorators.js.map +1 -1
  86. package/functions/arraysAreEquivalent.d.ts +9 -0
  87. package/functions/arraysAreEquivalent.js +28 -0
  88. package/functions/arraysAreEquivalent.js.map +1 -0
  89. package/functions/containsDeep.d.ts +2 -0
  90. package/functions/containsDeep.js +2 -0
  91. package/functions/containsDeep.js.map +1 -1
  92. package/functions/context.d.ts +3 -4
  93. package/functions/context.js +6 -2
  94. package/functions/context.js.map +1 -1
  95. package/functions/debounce.js.map +1 -1
  96. package/functions/isElementInView.d.ts +4 -6
  97. package/functions/isElementInView.js +9 -11
  98. package/functions/isElementInView.js.map +1 -1
  99. package/package.json +12 -4
  100. package/ssr-shims.d.ts +17 -0
  101. package/ssr-shims.js +55 -0
  102. package/ssr-shims.js.map +1 -0
@@ -7,6 +7,7 @@ function isObjectConfigSpread(config) {
7
7
  /**
8
8
  * If it's a named slot, return its children,
9
9
  * for the default slot, look for direct children not assigned to a slot
10
+ * @param n slot name
10
11
  */
11
12
  const isSlot = (n) => (child) => n === SlotController.default ? !child.hasAttribute('slot')
12
13
  : child.getAttribute('slot') === n;
@@ -39,7 +40,8 @@ export class SlotController {
39
40
  });
40
41
  _SlotController_initSlot.set(this, (slotName) => {
41
42
  const name = slotName || _a.default;
42
- const elements = __classPrivateFieldGet(this, _SlotController_nodes, "f").get(name)?.slot?.assignedElements?.() ?? __classPrivateFieldGet(this, _SlotController_instances, "m", _SlotController_getChildrenForSlot).call(this, name);
43
+ const elements = __classPrivateFieldGet(this, _SlotController_nodes, "f").get(name)?.slot?.assignedElements?.()
44
+ ?? __classPrivateFieldGet(this, _SlotController_instances, "m", _SlotController_getChildrenForSlot).call(this, name);
43
45
  const selector = slotName ? `slot[name="${slotName}"]` : 'slot:not([name])';
44
46
  const slot = this.host.shadowRoot?.querySelector?.(selector) ?? null;
45
47
  const hasContent = !!elements.length;
@@ -87,21 +89,19 @@ export class SlotController {
87
89
  /**
88
90
  * Given a slot name or slot names, returns elements assigned to the requested slots as an array.
89
91
  * If no value is provided, it returns all children not assigned to a slot (without a slot attribute).
90
- *
92
+ * @param slotNames slots to query
91
93
  * @example Get header-slotted elements
92
- * ```js
93
- * this.getSlotted('header')
94
- * ```
95
- *
94
+ * ```js
95
+ * this.getSlotted('header')
96
+ * ```
96
97
  * @example Get header- and footer-slotted elements
97
- * ```js
98
- * this.getSlotted('header', 'footer')
99
- * ```
100
- *
98
+ * ```js
99
+ * this.getSlotted('header', 'footer')
100
+ * ```
101
101
  * @example Get default-slotted elements
102
- * ```js
103
- * this.getSlotted();
104
- * ```
102
+ * ```js
103
+ * this.getSlotted();
104
+ * ```
105
105
  */
106
106
  getSlotted(...slotNames) {
107
107
  if (!slotNames.length) {
@@ -113,25 +113,22 @@ export class SlotController {
113
113
  }
114
114
  /**
115
115
  * Returns a boolean statement of whether or not any of those slots exists in the light DOM.
116
- *
117
116
  * @param names The slot names to check.
118
117
  * @example this.hasSlotted('header');
119
118
  */
120
119
  hasSlotted(...names) {
121
- const { anonymous } = _a;
122
- const slotNames = Array.from(names, x => x == null ? anonymous : x);
120
+ const slotNames = Array.from(names, x => x == null ? _a.default : x);
123
121
  if (!slotNames.length) {
124
- slotNames.push(anonymous);
122
+ slotNames.push(_a.default);
125
123
  }
126
124
  return slotNames.some(x => __classPrivateFieldGet(this, _SlotController_nodes, "f").get(x)?.hasContent ?? false);
127
125
  }
128
126
  /**
129
127
  * Whether or not all the requested slots are empty.
130
- *
131
- * @param slots The slot name. If no value is provided, it returns the default slot.
128
+ * @param names The slot names to query. If no value is provided, it returns the default slot.
132
129
  * @example this.isEmpty('header', 'footer');
133
130
  * @example this.isEmpty();
134
- * @returns {Boolean}
131
+ * @returns
135
132
  */
136
133
  isEmpty(...names) {
137
134
  return !this.hasSlotted(...names);
@@ -1 +1 @@
1
- {"version":3,"file":"slot-controller.js","sourceRoot":"","sources":["slot-controller.ts"],"names":[],"mappings":";;AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAgCrC,SAAS,oBAAoB,CAAC,MAA2C;IACvE,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AACpF,CAAC;AAED;;;GAGG;AACH,MAAM,MAAM,GACV,CAA8B,CAAyC,EAAE,EAAE,CACzE,CAAC,KAAc,EAAc,EAAE,CAC3B,CAAC,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC;IAC5D,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEzC,MAAM,OAAO,cAAc;IAiBzB,YAAmB,IAAqB,EAAE,GAAG,MAA2C;;QAArE,SAAI,GAAJ,IAAI,CAAiB;QAZxC,gCAAS,IAAI,GAAG,EAAgD,EAAC;QAEjE,yCAAgB;QAEhB,uCAAgB,KAAK,EAAC;QAEtB,6BAAM,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,uBAAA,IAAI,kCAAY,MAAhB,IAAI,EAAa,OAAO,CAAC,CAAC,EAAC;QAEjE,4CAA8B;QAE9B,uCAAwC,EAAE,EAAC;QAqG3C,uCAAgB,CAAC,KAA0C,EAAE,EAAE;YAC7D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;YACnC,uBAAA,IAAI,gCAAU,MAAd,IAAI,EAAW,QAAQ,CAAC,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC,EAAC;QAEF,qCAAc,KAAK,EAAE,OAAyB,EAAE,EAAE;YAChD,MAAM,OAAO,GAAG,EAAE,CAAC;YACnB,KAAK,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,OAAO,EAAE,CAAC;gBACnD,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAAC,EAAE,CAAC;oBACpD,IAAI,IAAI,YAAY,WAAW,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;wBAC7C,uBAAA,IAAI,gCAAU,MAAd,IAAI,EAAW,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC1B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1B,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC,EAAC;QAOF,mCAAY,CAAC,QAAuB,EAAE,EAAE;YACtC,MAAM,IAAI,GAAG,QAAQ,IAAI,EAAc,CAAC,OAAO,CAAC;YAChD,MAAM,QAAQ,GAAG,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,IAAI,uBAAA,IAAI,qEAAoB,MAAxB,IAAI,EAAqB,IAAI,CAAC,CAAC;YACrG,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,cAAc,QAAQ,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC;YAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,EAAE,CAAkB,QAAQ,CAAC,IAAI,IAAI,CAAC;YACtF,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YACrC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5E,uBAAA,IAAI,8BAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC3C,CAAC,EAAC;QAlIA,uBAAA,IAAI,0BAAW,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAA,CAAC;QAErC,IAAI,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC;YACzC,uBAAA,IAAI,6BAAc,KAAK,MAAA,CAAC;YACxB,uBAAA,IAAI,gCAAiB,YAAY,IAAI,EAAE,MAAA,CAAC;QAC1C,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAC9B,uBAAA,IAAI,6BAAc,MAAM,MAAA,CAAC;YACzB,uBAAA,IAAI,gCAAiB,EAAE,MAAA,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,uBAAA,IAAI,6BAAc,CAAC,IAAI,CAAC,MAAA,CAAC;QAC3B,CAAC;QAGD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,uBAAA,IAAI,oCAA+B,CAAC,CAAC;QAC9E,uBAAA,IAAI,gCAAiB,KAAK,MAAA,CAAC;QAC3B,uBAAA,IAAI,0BAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,+DAA+D;QAC/D,uBAAA,IAAI,6BAAO,CAAC,KAAK,EAAE,CAAC;QACpB,kDAAkD;QAClD,uBAAA,IAAI,iCAAW,CAAC,OAAO,CAAC,uBAAA,IAAI,gCAAU,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,uBAAA,IAAI,oCAAc,CAAC,CAAC,OAAO,CAAC,uBAAA,IAAI,gCAAU,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1B,uCAAuC;QACvC,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5B,CAAC;IAED,WAAW;QACT,IAAI,CAAC,uBAAA,IAAI,oCAAc,EAAE,CAAC;YACxB,uBAAA,IAAI,iCAAW,CAAC,OAAO,CAAC,uBAAA,IAAI,gCAAU,CAAC,CAAC;YACxC,uBAAA,IAAI,gCAAiB,IAAI,MAAA,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,gBAAgB;QACd,uBAAA,IAAI,0BAAI,CAAC,UAAU,EAAE,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CAA8B,GAAG,SAAmB;QAC5D,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,EAAc,CAAC,OAAO,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAQ,CAAC;QAC1E,CAAC;aAAM,CAAC;YACN,OAAO,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAClC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAQ,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,GAAG,KAAoC;QAChD,MAAM,EAAE,SAAS,EAAE,GAAG,EAAc,CAAC;QACrC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACtB,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IACtE,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,GAAG,KAAoC;QAC7C,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,CAAC;IACpC,CAAC;;+gBAqBgD,IAA4C;IAC3F,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAQ,CAAC;IACvD,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAzIa,sBAAO,GAAG,MAAM,CAAC,cAAc,CAAC,AAAzB,CAA0B;AAC/C,gCAAgC;AAClB,wBAAS,GAAG,EAAI,CAAC,OAAO,AAAf,CAAgB","sourcesContent":["import type { ReactiveController, ReactiveElement } from 'lit';\n\nimport { Logger } from './logger.js';\n\ninterface AnonymousSlot {\n hasContent: boolean;\n elements: Element[];\n slot: HTMLSlotElement | null;\n}\n\ninterface NamedSlot extends AnonymousSlot {\n name: string;\n initialized: true;\n}\n\nexport type Slot = NamedSlot | AnonymousSlot;\n\nexport interface SlotsConfig {\n slots: (string | null)[];\n /**\n * Object mapping new slot name keys to deprecated slot name values\n * @example `pf-modal--header` is deprecated in favour of `header`\n * ```js\n * new SlotController(this, {\n * slots: ['header'],\n * deprecations: {\n * 'header': 'pf-modal--header'\n * }\n * })\n * ```\n */\n deprecations?: Record<string, string>;\n}\n\nfunction isObjectConfigSpread(config: ([SlotsConfig] | (string | null)[])): config is [SlotsConfig] {\n return config.length === 1 && typeof config[0] === 'object' && config[0] !== null;\n}\n\n/**\n * If it's a named slot, return its children,\n * for the default slot, look for direct children not assigned to a slot\n */\nconst isSlot =\n <T extends Element = Element>(n: string | typeof SlotController.default) =>\n (child: Element): child is T =>\n n === SlotController.default ? !child.hasAttribute('slot')\n : child.getAttribute('slot') === n;\n\nexport class SlotController implements ReactiveController {\n public static default = Symbol('default slot');\n /** @deprecated use `default` */\n public static anonymous = this.default;\n\n #nodes = new Map<string | typeof SlotController.default, Slot>();\n\n #logger: Logger;\n\n #firstUpdated = false;\n\n #mo = new MutationObserver(records => this.#onMutation(records));\n\n #slotNames: (string | null)[];\n\n #deprecations: Record<string, string> = {};\n\n constructor(public host: ReactiveElement, ...config: ([SlotsConfig] | (string | null)[])) {\n this.#logger = new Logger(this.host);\n\n if (isObjectConfigSpread(config)) {\n const [{ slots, deprecations }] = config;\n this.#slotNames = slots;\n this.#deprecations = deprecations ?? {};\n } else if (config.length >= 1) {\n this.#slotNames = config;\n this.#deprecations = {};\n } else {\n this.#slotNames = [null];\n }\n\n\n host.addController(this);\n }\n\n async hostConnected() {\n this.host.addEventListener('slotchange', this.#onSlotChange as EventListener);\n this.#firstUpdated = false;\n this.#mo.observe(this.host, { childList: true });\n // Map the defined slots into an object that is easier to query\n this.#nodes.clear();\n // Loop over the properties provided by the schema\n this.#slotNames.forEach(this.#initSlot);\n Object.values(this.#deprecations).forEach(this.#initSlot);\n this.host.requestUpdate();\n // insurance for framework integrations\n await this.host.updateComplete;\n this.host.requestUpdate();\n }\n\n hostUpdated() {\n if (!this.#firstUpdated) {\n this.#slotNames.forEach(this.#initSlot);\n this.#firstUpdated = true;\n }\n }\n\n hostDisconnected() {\n this.#mo.disconnect();\n }\n\n /**\n * Given a slot name or slot names, returns elements assigned to the requested slots as an array.\n * If no value is provided, it returns all children not assigned to a slot (without a slot attribute).\n *\n * @example Get header-slotted elements\n * ```js\n * this.getSlotted('header')\n * ```\n *\n * @example Get header- and footer-slotted elements\n * ```js\n * this.getSlotted('header', 'footer')\n * ```\n *\n * @example Get default-slotted elements\n * ```js\n * this.getSlotted();\n * ```\n */\n getSlotted<T extends Element = Element>(...slotNames: string[]): T[] {\n if (!slotNames.length) {\n return (this.#nodes.get(SlotController.default)?.elements ?? []) as T[];\n } else {\n return slotNames.flatMap(slotName =>\n this.#nodes.get(slotName)?.elements ?? []) as T[];\n }\n }\n\n /**\n * Returns a boolean statement of whether or not any of those slots exists in the light DOM.\n *\n * @param names The slot names to check.\n * @example this.hasSlotted('header');\n */\n hasSlotted(...names: (string | null | undefined)[]): boolean {\n const { anonymous } = SlotController;\n const slotNames = Array.from(names, x => x == null ? anonymous : x);\n if (!slotNames.length) {\n slotNames.push(anonymous);\n }\n return slotNames.some(x => this.#nodes.get(x)?.hasContent ?? false);\n }\n\n /**\n * Whether or not all the requested slots are empty.\n *\n * @param slots The slot name. If no value is provided, it returns the default slot.\n * @example this.isEmpty('header', 'footer');\n * @example this.isEmpty();\n * @returns {Boolean}\n */\n isEmpty(...names: (string | null | undefined)[]): boolean {\n return !this.hasSlotted(...names);\n }\n\n #onSlotChange = (event: Event & { target: HTMLSlotElement }) => {\n const slotName = event.target.name;\n this.#initSlot(slotName);\n this.host.requestUpdate();\n };\n\n #onMutation = async (records: MutationRecord[]) => {\n const changed = [];\n for (const { addedNodes, removedNodes } of records) {\n for (const node of [...addedNodes, ...removedNodes]) {\n if (node instanceof HTMLElement && node.slot) {\n this.#initSlot(node.slot);\n changed.push(node.slot);\n }\n }\n }\n this.host.requestUpdate();\n };\n\n #getChildrenForSlot<T extends Element = Element>(name: string | typeof SlotController.default): T[] {\n const children = Array.from(this.host.children) as T[];\n return children.filter(isSlot(name));\n }\n\n #initSlot = (slotName: string | null) => {\n const name = slotName || SlotController.default;\n const elements = this.#nodes.get(name)?.slot?.assignedElements?.() ?? this.#getChildrenForSlot(name);\n const selector = slotName ? `slot[name=\"${slotName}\"]` : 'slot:not([name])';\n const slot = this.host.shadowRoot?.querySelector?.<HTMLSlotElement>(selector) ?? null;\n const hasContent = !!elements.length;\n this.#nodes.set(name, { elements, name: slotName ?? '', hasContent, slot });\n this.#logger.debug(slotName, hasContent);\n };\n}\n"]}
1
+ {"version":3,"file":"slot-controller.js","sourceRoot":"","sources":["slot-controller.ts"],"names":[],"mappings":";;AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAgCrC,SAAS,oBAAoB,CAC3B,MAA2C;IAE3C,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,MAAM,GACV,CAA8B,CAAyC,EAAE,EAAE,CACzE,CAAC,KAAc,EAAc,EAAE,CAC3B,CAAC,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC;IAC5D,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEzC,MAAM,OAAO,cAAc;IAkBzB,YAAmB,IAAqB,EAAE,GAAG,MAA2C;;QAArE,SAAI,GAAJ,IAAI,CAAiB;QAZxC,gCAAS,IAAI,GAAG,EAAgD,EAAC;QAEjE,yCAAgB;QAEhB,uCAAgB,KAAK,EAAC;QAEtB,6BAAM,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,uBAAA,IAAI,kCAAY,MAAhB,IAAI,EAAa,OAAO,CAAC,CAAC,EAAC;QAEjE,4CAA8B;QAE9B,uCAAwC,EAAE,EAAC;QAgG3C,uCAAgB,CAAC,KAA0C,EAAE,EAAE;YAC7D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;YACnC,uBAAA,IAAI,gCAAU,MAAd,IAAI,EAAW,QAAQ,CAAC,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC,EAAC;QAEF,qCAAc,KAAK,EAAE,OAAyB,EAAE,EAAE;YAChD,MAAM,OAAO,GAAG,EAAE,CAAC;YACnB,KAAK,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,OAAO,EAAE,CAAC;gBACnD,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAAC,EAAE,CAAC;oBACpD,IAAI,IAAI,YAAY,WAAW,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;wBAC7C,uBAAA,IAAI,gCAAU,MAAd,IAAI,EAAW,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC1B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1B,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC,EAAC;QASF,mCAAY,CAAC,QAAuB,EAAE,EAAE;YACtC,MAAM,IAAI,GAAG,QAAQ,IAAI,EAAc,CAAC,OAAO,CAAC;YAChD,MAAM,QAAQ,GAAG,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE;mBAC7D,uBAAA,IAAI,qEAAoB,MAAxB,IAAI,EAAqB,IAAI,CAAC,CAAC;YACpC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,cAAc,QAAQ,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC;YAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,EAAE,CAAkB,QAAQ,CAAC,IAAI,IAAI,CAAC;YACtF,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YACrC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5E,uBAAA,IAAI,8BAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC3C,CAAC,EAAC;QAhIA,uBAAA,IAAI,0BAAW,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAA,CAAC;QAErC,IAAI,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC;YACzC,uBAAA,IAAI,6BAAc,KAAK,MAAA,CAAC;YACxB,uBAAA,IAAI,gCAAiB,YAAY,IAAI,EAAE,MAAA,CAAC;QAC1C,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAC9B,uBAAA,IAAI,6BAAc,MAAM,MAAA,CAAC;YACzB,uBAAA,IAAI,gCAAiB,EAAE,MAAA,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,uBAAA,IAAI,6BAAc,CAAC,IAAI,CAAC,MAAA,CAAC;QAC3B,CAAC;QAGD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,uBAAA,IAAI,oCAA+B,CAAC,CAAC;QAC9E,uBAAA,IAAI,gCAAiB,KAAK,MAAA,CAAC;QAC3B,uBAAA,IAAI,0BAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,+DAA+D;QAC/D,uBAAA,IAAI,6BAAO,CAAC,KAAK,EAAE,CAAC;QACpB,kDAAkD;QAClD,uBAAA,IAAI,iCAAW,CAAC,OAAO,CAAC,uBAAA,IAAI,gCAAU,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,uBAAA,IAAI,oCAAc,CAAC,CAAC,OAAO,CAAC,uBAAA,IAAI,gCAAU,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1B,uCAAuC;QACvC,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5B,CAAC;IAED,WAAW;QACT,IAAI,CAAC,uBAAA,IAAI,oCAAc,EAAE,CAAC;YACxB,uBAAA,IAAI,iCAAW,CAAC,OAAO,CAAC,uBAAA,IAAI,gCAAU,CAAC,CAAC;YACxC,uBAAA,IAAI,gCAAiB,IAAI,MAAA,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,gBAAgB;QACd,uBAAA,IAAI,0BAAI,CAAC,UAAU,EAAE,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAA8B,GAAG,SAAmB;QAC5D,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,EAAc,CAAC,OAAO,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAQ,CAAC;QAC1E,CAAC;aAAM,CAAC;YACN,OAAO,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAClC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAQ,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,GAAG,KAAoC;QAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACtB,SAAS,CAAC,IAAI,CAAC,EAAc,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,uBAAA,IAAI,6BAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IACtE,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,KAAoC;QAC7C,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,CAAC;IACpC,CAAC;;+gBAsBC,IAA4C;IAE5C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAQ,CAAC;IACvD,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAvIa,sBAAO,GAAG,MAAM,CAAC,cAAc,CAA4B,AAApD,CAAqD;AAE1E,gCAAgC;AAClB,wBAAS,GAAW,EAAI,CAAC,OAAO,AAAvB,CAAwB","sourcesContent":["import type { ReactiveController, ReactiveElement } from 'lit';\n\nimport { Logger } from './logger.js';\n\ninterface AnonymousSlot {\n hasContent: boolean;\n elements: Element[];\n slot: HTMLSlotElement | null;\n}\n\ninterface NamedSlot extends AnonymousSlot {\n name: string;\n initialized: true;\n}\n\nexport type Slot = NamedSlot | AnonymousSlot;\n\nexport interface SlotsConfig {\n slots: (string | null)[];\n /**\n * Object mapping new slot name keys to deprecated slot name values\n * @example `pf-modal--header` is deprecated in favour of `header`\n * ```js\n * new SlotController(this, {\n * slots: ['header'],\n * deprecations: {\n * 'header': 'pf-modal--header'\n * }\n * })\n * ```\n */\n deprecations?: Record<string, string>;\n}\n\nfunction isObjectConfigSpread(\n config: ([SlotsConfig] | (string | null)[]),\n): config is [SlotsConfig] {\n return config.length === 1 && typeof config[0] === 'object' && config[0] !== null;\n}\n\n/**\n * If it's a named slot, return its children,\n * for the default slot, look for direct children not assigned to a slot\n * @param n slot name\n */\nconst isSlot =\n <T extends Element = Element>(n: string | typeof SlotController.default) =>\n (child: Element): child is T =>\n n === SlotController.default ? !child.hasAttribute('slot')\n : child.getAttribute('slot') === n;\n\nexport class SlotController implements ReactiveController {\n public static default = Symbol('default slot') satisfies symbol as symbol;\n\n /** @deprecated use `default` */\n public static anonymous: symbol = this.default;\n\n #nodes = new Map<string | typeof SlotController.default, Slot>();\n\n #logger: Logger;\n\n #firstUpdated = false;\n\n #mo = new MutationObserver(records => this.#onMutation(records));\n\n #slotNames: (string | null)[];\n\n #deprecations: Record<string, string> = {};\n\n constructor(public host: ReactiveElement, ...config: ([SlotsConfig] | (string | null)[])) {\n this.#logger = new Logger(this.host);\n\n if (isObjectConfigSpread(config)) {\n const [{ slots, deprecations }] = config;\n this.#slotNames = slots;\n this.#deprecations = deprecations ?? {};\n } else if (config.length >= 1) {\n this.#slotNames = config;\n this.#deprecations = {};\n } else {\n this.#slotNames = [null];\n }\n\n\n host.addController(this);\n }\n\n async hostConnected(): Promise<void> {\n this.host.addEventListener('slotchange', this.#onSlotChange as EventListener);\n this.#firstUpdated = false;\n this.#mo.observe(this.host, { childList: true });\n // Map the defined slots into an object that is easier to query\n this.#nodes.clear();\n // Loop over the properties provided by the schema\n this.#slotNames.forEach(this.#initSlot);\n Object.values(this.#deprecations).forEach(this.#initSlot);\n this.host.requestUpdate();\n // insurance for framework integrations\n await this.host.updateComplete;\n this.host.requestUpdate();\n }\n\n hostUpdated(): void {\n if (!this.#firstUpdated) {\n this.#slotNames.forEach(this.#initSlot);\n this.#firstUpdated = true;\n }\n }\n\n hostDisconnected(): void {\n this.#mo.disconnect();\n }\n\n /**\n * Given a slot name or slot names, returns elements assigned to the requested slots as an array.\n * If no value is provided, it returns all children not assigned to a slot (without a slot attribute).\n * @param slotNames slots to query\n * @example Get header-slotted elements\n * ```js\n * this.getSlotted('header')\n * ```\n * @example Get header- and footer-slotted elements\n * ```js\n * this.getSlotted('header', 'footer')\n * ```\n * @example Get default-slotted elements\n * ```js\n * this.getSlotted();\n * ```\n */\n getSlotted<T extends Element = Element>(...slotNames: string[]): T[] {\n if (!slotNames.length) {\n return (this.#nodes.get(SlotController.default)?.elements ?? []) as T[];\n } else {\n return slotNames.flatMap(slotName =>\n this.#nodes.get(slotName)?.elements ?? []) as T[];\n }\n }\n\n /**\n * Returns a boolean statement of whether or not any of those slots exists in the light DOM.\n * @param names The slot names to check.\n * @example this.hasSlotted('header');\n */\n hasSlotted(...names: (string | null | undefined)[]): boolean {\n const slotNames = Array.from(names, x => x == null ? SlotController.default : x);\n if (!slotNames.length) {\n slotNames.push(SlotController.default);\n }\n return slotNames.some(x => this.#nodes.get(x)?.hasContent ?? false);\n }\n\n /**\n * Whether or not all the requested slots are empty.\n * @param names The slot names to query. If no value is provided, it returns the default slot.\n * @example this.isEmpty('header', 'footer');\n * @example this.isEmpty();\n * @returns\n */\n isEmpty(...names: (string | null | undefined)[]): boolean {\n return !this.hasSlotted(...names);\n }\n\n #onSlotChange = (event: Event & { target: HTMLSlotElement }) => {\n const slotName = event.target.name;\n this.#initSlot(slotName);\n this.host.requestUpdate();\n };\n\n #onMutation = async (records: MutationRecord[]) => {\n const changed = [];\n for (const { addedNodes, removedNodes } of records) {\n for (const node of [...addedNodes, ...removedNodes]) {\n if (node instanceof HTMLElement && node.slot) {\n this.#initSlot(node.slot);\n changed.push(node.slot);\n }\n }\n }\n this.host.requestUpdate();\n };\n\n #getChildrenForSlot<T extends Element = Element>(\n name: string | typeof SlotController.default,\n ): T[] {\n const children = Array.from(this.host.children) as T[];\n return children.filter(isSlot(name));\n }\n\n #initSlot = (slotName: string | null) => {\n const name = slotName || SlotController.default;\n const elements = this.#nodes.get(name)?.slot?.assignedElements?.()\n ?? this.#getChildrenForSlot(name);\n const selector = slotName ? `slot[name=\"${slotName}\"]` : 'slot:not([name])';\n const slot = this.host.shadowRoot?.querySelector?.<HTMLSlotElement>(selector) ?? null;\n const hasContent = !!elements.length;\n this.#nodes.set(name, { elements, name: slotName ?? '', hasContent, slot });\n this.#logger.debug(slotName, hasContent);\n };\n}\n"]}
@@ -17,7 +17,9 @@ export class StyleController {
17
17
  if (this.stylesAdopted || !(this.host.renderRoot instanceof ShadowRoot)) {
18
18
  return;
19
19
  }
20
- const styles = [this.styles].flatMap(x => getCompatibleStyle(x)).filter(x => !!x);
20
+ const styles = [this.styles]
21
+ .flatMap(x => getCompatibleStyle(x))
22
+ .filter(x => !!x);
21
23
  if (supportsAdoptingStyleSheets) {
22
24
  this.host.renderRoot.adoptedStyleSheets = [
23
25
  ...styles.map(x => x instanceof CSSStyleSheet ? x : x.styleSheet),
@@ -1 +1 @@
1
- {"version":3,"file":"style-controller.js","sourceRoot":"","sources":["style-controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,KAAK,CAAC;AAQtE;;;;GAIG;AACH,MAAM,OAAO,eAAe;IAG1B,YACU,IAAqB;IAC7B,uDAAuD;IAC/C,MAAsB;QAFtB,SAAI,GAAJ,IAAI,CAAiB;QAErB,WAAM,GAAN,MAAM,CAAgB;QALxB,kBAAa,GAAG,KAAK,CAAC;QAO5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,aAAa;QACX,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,YAAY,UAAU,CAAC,EAAE,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAsB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEvG,IAAI,2BAA2B,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,GAAG;gBACxC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAA2B,CAAC;gBAClF,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,IAAI,EAAE;aACjD,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;gBACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;gBAC9C,8DAA8D;gBAC9D,MAAM,KAAK,GAAI,MAAc,CAAC,UAAU,CAAC,CAAC;gBAC1C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBACrC,CAAC;gBACD,KAAK,CAAC,WAAW,GAAI,CAAe,CAAC,OAAO,CAAC;gBAC7C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;CACF","sourcesContent":["import type { ReactiveController, ReactiveElement, CSSResultGroup, CSSResultOrNative, CSSResult } from 'lit';\nimport { getCompatibleStyle, supportsAdoptingStyleSheets } from 'lit';\n\ndeclare global {\n interface ShadowRoot {\n adoptedStyleSheets: CSSStyleSheet[];\n }\n}\n\n/**\n * Controller which adds styles to it's host element.\n * Like `static styles = []`, except a controller.\n * Should typically only be used within other controllers.\n */\nexport class StyleController implements ReactiveController {\n private stylesAdopted = false;\n\n constructor(\n private host: ReactiveElement,\n /** These styles will be applied to the host element */\n private styles: CSSResultGroup,\n ) {\n host.addController(this);\n }\n\n hostConnected(): void {\n if (this.stylesAdopted || !(this.host.renderRoot instanceof ShadowRoot)) {\n return;\n }\n\n const styles = [this.styles].flatMap(x => getCompatibleStyle(x as CSSResultOrNative)).filter(x => !!x);\n\n if (supportsAdoptingStyleSheets) {\n this.host.renderRoot.adoptedStyleSheets = [\n ...styles.map(x => x instanceof CSSStyleSheet ? x : x.styleSheet as CSSStyleSheet),\n ...this.host.renderRoot.adoptedStyleSheets ?? [],\n ];\n } else {\n styles.forEach(s => {\n const style = document.createElement('style');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const nonce = (window as any)['litNonce'];\n if (nonce !== undefined) {\n style.setAttribute('nonce', nonce);\n }\n style.textContent = (s as CSSResult).cssText;\n this.host.renderRoot.appendChild(style);\n });\n }\n\n this.stylesAdopted = true;\n }\n}\n"]}
1
+ {"version":3,"file":"style-controller.js","sourceRoot":"","sources":["style-controller.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,KAAK,CAAC;AAQtE;;;;GAIG;AACH,MAAM,OAAO,eAAe;IAG1B,YACU,IAAqB;IAC7B,uDAAuD;IAC/C,MAAsB;QAFtB,SAAI,GAAJ,IAAI,CAAiB;QAErB,WAAM,GAAN,MAAM,CAAgB;QALxB,kBAAa,GAAG,KAAK,CAAC;QAO5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,aAAa;QACX,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,YAAY,UAAU,CAAC,EAAE,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;aACvB,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAsB,CAAC,CAAC;aACxD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtB,IAAI,2BAA2B,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,GAAG;gBACxC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAA2B,CAAC;gBAClF,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,IAAI,EAAE;aACjD,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;gBACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;gBAC9C,8DAA8D;gBAC9D,MAAM,KAAK,GAAI,MAAc,CAAC,UAAU,CAAC,CAAC;gBAC1C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBACrC,CAAC;gBACD,KAAK,CAAC,WAAW,GAAI,CAAe,CAAC,OAAO,CAAC;gBAC7C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;CACF","sourcesContent":["import type {\n ReactiveController,\n ReactiveElement,\n CSSResultGroup,\n CSSResultOrNative,\n CSSResult,\n} from 'lit';\nimport { getCompatibleStyle, supportsAdoptingStyleSheets } from 'lit';\n\ndeclare global {\n interface ShadowRoot {\n adoptedStyleSheets: CSSStyleSheet[];\n }\n}\n\n/**\n * Controller which adds styles to it's host element.\n * Like `static styles = []`, except a controller.\n * Should typically only be used within other controllers.\n */\nexport class StyleController implements ReactiveController {\n private stylesAdopted = false;\n\n constructor(\n private host: ReactiveElement,\n /** These styles will be applied to the host element */\n private styles: CSSResultGroup,\n ) {\n host.addController(this);\n }\n\n hostConnected(): void {\n if (this.stylesAdopted || !(this.host.renderRoot instanceof ShadowRoot)) {\n return;\n }\n\n const styles = [this.styles]\n .flatMap(x => getCompatibleStyle(x as CSSResultOrNative))\n .filter(x => !!x);\n\n if (supportsAdoptingStyleSheets) {\n this.host.renderRoot.adoptedStyleSheets = [\n ...styles.map(x => x instanceof CSSStyleSheet ? x : x.styleSheet as CSSStyleSheet),\n ...this.host.renderRoot.adoptedStyleSheets ?? [],\n ];\n } else {\n styles.forEach(s => {\n const style = document.createElement('style');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const nonce = (window as any)['litNonce'];\n if (nonce !== undefined) {\n style.setAttribute('nonce', nonce);\n }\n style.textContent = (s as CSSResult).cssText;\n this.host.renderRoot.appendChild(style);\n });\n }\n\n this.stylesAdopted = true;\n }\n}\n"]}
@@ -12,6 +12,8 @@ export declare class TabsAriaController<Tab extends HTMLElement = HTMLElement, P
12
12
  get tabs(): Tab[];
13
13
  get activeTab(): Tab | undefined;
14
14
  /**
15
+ * @param host controller host
16
+ * @param options controller options
15
17
  * @example Usage in PfTab
16
18
  * ```ts
17
19
  * new TabsController(this, {
@@ -9,6 +9,8 @@ export class TabsAriaController {
9
9
  return this.tabs.find(x => __classPrivateFieldGet(this, _TabsAriaController_options, "f").isActiveTab(x));
10
10
  }
11
11
  /**
12
+ * @param host controller host
13
+ * @param options controller options
12
14
  * @example Usage in PfTab
13
15
  * ```ts
14
16
  * new TabsController(this, {
@@ -1 +1 @@
1
- {"version":3,"file":"tabs-aria-controller.js","sourceRoot":"","sources":["tabs-aria-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nimport { Logger } from '@patternfly/pfe-core/controllers/logger.js';\n\nexport interface TabsAriaControllerOptions<Tab, Panel> {\n /** Add an `isTab` predicate to ensure this tabs instance' state does not leak into parent tabs' state */\n isTab: (node: unknown) => node is Tab;\n isActiveTab: (tab: Tab) => boolean;\n /** Add an `isPanel` predicate to ensure this tabs instance' state does not leak into parent tabs' state */\n isPanel: (node: unknown) => node is Panel;\n getHTMLElement?: () => HTMLElement;\n}\n\nexport class TabsAriaController<\n Tab extends HTMLElement = HTMLElement,\n Panel extends HTMLElement = HTMLElement,\n> implements ReactiveController {\n #logger: Logger;\n\n #host: ReactiveControllerHost;\n\n #element: HTMLElement;\n\n #tabPanelMap = new Map<Tab, Panel>();\n\n #options: TabsAriaControllerOptions<Tab, Panel>;\n\n #mo = new MutationObserver(this.#onSlotchange.bind(this));\n\n get tabs() {\n return [...this.#tabPanelMap.keys()] as Tab[];\n }\n\n get activeTab(): Tab | undefined {\n return this.tabs.find(x => this.#options.isActiveTab(x));\n }\n\n /**\n * @example Usage in PfTab\n * ```ts\n * new TabsController(this, {\n * isTab: (x): x is PfTab => x instanceof PfTab,\n * isPanel: (x): x is PfTabPanel => x instanceof PfTabPanel\n * });\n * ```\n */\n constructor(\n host: ReactiveControllerHost,\n options: TabsAriaControllerOptions<Tab, Panel>,\n ) {\n this.#options = options;\n this.#logger = new Logger(host);\n if (host instanceof HTMLElement) {\n this.#element = host;\n } else {\n const element = options.getHTMLElement?.();\n if (!element) {\n throw new Error('TabsController must be instantiated with an HTMLElement or a `getHTMLElement()` option');\n }\n this.#element = element;\n }\n (this.#host = host).addController(this);\n this.#element.addEventListener('slotchange', this.#onSlotchange);\n if (this.#element.isConnected) {\n this.hostConnected();\n }\n }\n\n hostConnected() {\n this.#mo.observe(this.#element, { attributes: false, childList: true, subtree: false });\n this.#onSlotchange();\n }\n\n hostUpdated() {\n for (const [tab, panel] of this.#tabPanelMap) {\n panel.setAttribute('aria-labelledby', tab.id);\n tab.setAttribute('aria-controls', panel.id);\n }\n }\n\n hostDisconnected(): void {\n this.#mo.disconnect();\n }\n\n /**\n * zip the tabs and panels together into #tabPanelMap\n */\n #onSlotchange() {\n this.#tabPanelMap.clear();\n const tabs = [];\n const panels = [];\n for (const child of this.#element.children) {\n if (this.#options.isTab(child)) {\n tabs.push(child);\n child.role ??= 'tab';\n } else if (this.#options.isPanel(child)) {\n panels.push(child);\n child.role ??= 'tabpanel';\n }\n }\n if (tabs.length > panels.length) {\n this.#logger.warn('Too many tabs!');\n } else if (panels.length > tabs.length) {\n this.#logger.warn('Too many panels!');\n }\n while (tabs.length) {\n this.#tabPanelMap.set(tabs.shift()!, panels.shift()!);\n }\n this.#host.requestUpdate();\n }\n\n panelFor(tab: Tab): Panel | undefined {\n return this.#tabPanelMap.get(tab);\n }\n\n tabFor(panel: Panel): Tab | undefined {\n for (const [tab, panelToCheck] of this.#tabPanelMap) {\n if (panel === panelToCheck) {\n return tab;\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"tabs-aria-controller.js","sourceRoot":"","sources":["tabs-aria-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nimport { Logger } from '@patternfly/pfe-core/controllers/logger.js';\n\nexport interface TabsAriaControllerOptions<Tab, Panel> {\n /** Add an `isTab` predicate to ensure this tabs instance' state does not leak into parent tabs' state */\n isTab: (node: unknown) => node is Tab;\n isActiveTab: (tab: Tab) => boolean;\n /** Add an `isPanel` predicate to ensure this tabs instance' state does not leak into parent tabs' state */\n isPanel: (node: unknown) => node is Panel;\n getHTMLElement?: () => HTMLElement;\n}\n\nexport class TabsAriaController<\n Tab extends HTMLElement = HTMLElement,\n Panel extends HTMLElement = HTMLElement\n> implements ReactiveController {\n #logger: Logger;\n\n #host: ReactiveControllerHost;\n\n #element: HTMLElement;\n\n #tabPanelMap = new Map<Tab, Panel>();\n\n #options: TabsAriaControllerOptions<Tab, Panel>;\n\n #mo = new MutationObserver(this.#onSlotchange.bind(this));\n\n get tabs() {\n return [...this.#tabPanelMap.keys()] as Tab[];\n }\n\n get activeTab(): Tab | undefined {\n return this.tabs.find(x => this.#options.isActiveTab(x));\n }\n\n /**\n * @param host controller host\n * @param options controller options\n * @example Usage in PfTab\n * ```ts\n * new TabsController(this, {\n * isTab: (x): x is PfTab => x instanceof PfTab,\n * isPanel: (x): x is PfTabPanel => x instanceof PfTabPanel\n * });\n * ```\n */\n constructor(\n host: ReactiveControllerHost,\n options: TabsAriaControllerOptions<Tab, Panel>,\n ) {\n this.#options = options;\n this.#logger = new Logger(host);\n if (host instanceof HTMLElement) {\n this.#element = host;\n } else {\n const element = options.getHTMLElement?.();\n if (!element) {\n throw new Error(\n 'TabsController must be instantiated with an HTMLElement or a `getHTMLElement()` option',\n );\n }\n this.#element = element;\n }\n (this.#host = host).addController(this);\n this.#element.addEventListener('slotchange', this.#onSlotchange);\n if (this.#element.isConnected) {\n this.hostConnected();\n }\n }\n\n hostConnected(): void {\n this.#mo.observe(this.#element, { attributes: false, childList: true, subtree: false });\n this.#onSlotchange();\n }\n\n hostUpdated(): void {\n for (const [tab, panel] of this.#tabPanelMap) {\n panel.setAttribute('aria-labelledby', tab.id);\n tab.setAttribute('aria-controls', panel.id);\n }\n }\n\n hostDisconnected(): void {\n this.#mo.disconnect();\n }\n\n /**\n * zip the tabs and panels together into #tabPanelMap\n */\n #onSlotchange() {\n this.#tabPanelMap.clear();\n const tabs = [];\n const panels = [];\n for (const child of this.#element.children) {\n if (this.#options.isTab(child)) {\n tabs.push(child);\n child.role ??= 'tab';\n } else if (this.#options.isPanel(child)) {\n panels.push(child);\n child.role ??= 'tabpanel';\n }\n }\n if (tabs.length > panels.length) {\n this.#logger.warn('Too many tabs!');\n } else if (panels.length > tabs.length) {\n this.#logger.warn('Too many panels!');\n }\n while (tabs.length) {\n this.#tabPanelMap.set(tabs.shift()!, panels.shift()!);\n }\n this.#host.requestUpdate();\n }\n\n panelFor(tab: Tab): Panel | undefined {\n return this.#tabPanelMap.get(tab);\n }\n\n tabFor(panel: Panel): Tab | undefined {\n for (const [tab, panelToCheck] of this.#tabPanelMap) {\n if (panel === panelToCheck) {\n return tab;\n }\n }\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,282 @@
1
+ var _a;
2
+ import { __decorate } from "tslib";
3
+ import { expect, fixture, nextFrame } from '@open-wc/testing';
4
+ import { sendKeys } from '@web/test-runner-commands';
5
+ import { a11ySnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js';
6
+ import { customElement } from 'lit/decorators/custom-element.js';
7
+ import { query } from 'lit/decorators/query.js';
8
+ import { ReactiveElement, html, render } from 'lit';
9
+ import { ComboboxController } from '../combobox-controller.js';
10
+ function press(key) {
11
+ return async function () {
12
+ await sendKeys({ press: key });
13
+ };
14
+ }
15
+ class TestCombobox extends ReactiveElement {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.controller = ComboboxController.of(this, {
19
+ multi: false,
20
+ getItems: () => this.options,
21
+ isItem: item => item instanceof HTMLOptionElement,
22
+ getFallbackLabel: () => 'options',
23
+ getListboxElement: () => this.listbox ?? null,
24
+ getToggleButton: () => this.button ?? null,
25
+ getComboboxInput: () => this.combobox ?? null,
26
+ isExpanded: () => !this.listbox.hidden,
27
+ requestShowListbox: () => void (this.listbox.hidden = false),
28
+ requestHideListbox: () => void (this.listbox.hidden = true),
29
+ setItemActive: (item, active) => item.classList.toggle('active', active),
30
+ setItemSelected: (item, selected) => item.selected = selected,
31
+ });
32
+ }
33
+ /** List of options */
34
+ get options() {
35
+ return [
36
+ ...new Set([
37
+ this.placeholder,
38
+ ...this.querySelectorAll('option'),
39
+ ...this.renderRoot.querySelectorAll('option'),
40
+ ]),
41
+ ].filter(x => !!x);
42
+ }
43
+ get selected() {
44
+ return this.options.filter(x => x.selected);
45
+ }
46
+ get activeOption() {
47
+ return this.options.find(x => x.classList.contains('active'));
48
+ }
49
+ update(changed) {
50
+ render(this.render(), this.renderRoot);
51
+ super.update(changed);
52
+ this.placeholder.inert = !!this.controller.selected.length;
53
+ }
54
+ connectedCallback() {
55
+ super.connectedCallback();
56
+ const root = this.renderRoot.getRootNode();
57
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets ?? [], _a.styles];
58
+ }
59
+ static async test() {
60
+ let element;
61
+ const updateComplete = () => element.updateComplete;
62
+ const { template } = this;
63
+ if (!template) {
64
+ throw new Error(`${this.constructor.name} must implement template`);
65
+ }
66
+ beforeEach(async function () {
67
+ element = await fixture(template);
68
+ });
69
+ describe('Tab', function () {
70
+ beforeEach(press('Tab'));
71
+ beforeEach(updateComplete);
72
+ it('focuses the combobox', async function () {
73
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
74
+ });
75
+ describe('Tab', function () {
76
+ beforeEach(press('Tab'));
77
+ beforeEach(updateComplete);
78
+ beforeEach(nextFrame);
79
+ it('does not focus the toggle button', async function () {
80
+ expect(await a11ySnapshot()).to.not.axContainQuery({ focused: true });
81
+ });
82
+ });
83
+ describe('ArrowDown', function () {
84
+ beforeEach(press('ArrowDown'));
85
+ beforeEach(updateComplete);
86
+ it('expands the listbox', async function () {
87
+ expect(await a11ySnapshot())
88
+ .to.axContainRole('listbox')
89
+ .and
90
+ .to.axContainQuery({ role: 'combobox', expanded: true });
91
+ });
92
+ it('maintains DOM focus on the combobox', async function () {
93
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
94
+ });
95
+ it('sets active state on the placeholder', function () {
96
+ expect(element.activeOption).to.equal(element.placeholder);
97
+ });
98
+ describe('Enter', function () {
99
+ beforeEach(press('Enter'));
100
+ beforeEach(updateComplete);
101
+ it('maintains DOM focus on the combobox', async function () {
102
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
103
+ });
104
+ it('selects nothing', function () {
105
+ expect(element.selected).to.have.length(0);
106
+ });
107
+ });
108
+ describe('ArrowDown', function () {
109
+ beforeEach(press('ArrowDown'));
110
+ beforeEach(updateComplete);
111
+ it('maintains DOM focus on the combobox', async function () {
112
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
113
+ });
114
+ it('sets active state on the 1st option', function () {
115
+ expect(element.activeOption).to.have.text('1');
116
+ });
117
+ describe('Enter', function () {
118
+ beforeEach(press('Enter'));
119
+ beforeEach(updateComplete);
120
+ it('maintains DOM focus on the combobox', async function () {
121
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
122
+ });
123
+ it('selects the first option', function () {
124
+ expect(element.selected).to.have.length(1);
125
+ expect(element.selected.at(0)).to.have.text('1');
126
+ });
127
+ it('collapses the listbox', async function () {
128
+ expect(await a11ySnapshot())
129
+ .to.not.axContainRole('listbox')
130
+ .and
131
+ .to.axContainQuery({ role: 'combobox', expanded: false });
132
+ });
133
+ });
134
+ });
135
+ describe('Escape', function () {
136
+ beforeEach(press('Escape'));
137
+ beforeEach(updateComplete);
138
+ it('collapses the listbox', async function () {
139
+ expect(await a11ySnapshot())
140
+ .to.not.axContainRole('listbox')
141
+ .and
142
+ .to.axContainQuery({ role: 'combobox', expanded: false });
143
+ });
144
+ it('maintains DOM focus on the combobox', async function () {
145
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
146
+ });
147
+ });
148
+ });
149
+ });
150
+ }
151
+ ;
152
+ }
153
+ _a = TestCombobox;
154
+ TestCombobox.styles = new CSSStyleSheet();
155
+ (() => {
156
+ _a.styles.replaceSync(/* css */ `
157
+ option {
158
+ &.active {
159
+ outline: 1px solid black;
160
+ }
161
+ &[selected] {
162
+ background: lightblue;
163
+ }
164
+ }
165
+ `);
166
+ })();
167
+ __decorate([
168
+ query('#listbox')
169
+ ], TestCombobox.prototype, "listbox", void 0);
170
+ __decorate([
171
+ query('#button')
172
+ ], TestCombobox.prototype, "button", void 0);
173
+ __decorate([
174
+ query('#combobox')
175
+ ], TestCombobox.prototype, "combobox", void 0);
176
+ __decorate([
177
+ query('#placeholder')
178
+ ], TestCombobox.prototype, "placeholder", void 0);
179
+ let XComboboxCrossRoot = class XComboboxCrossRoot extends TestCombobox {
180
+ /** List of options */
181
+ get options() {
182
+ return [
183
+ ...new Set([
184
+ this.placeholder,
185
+ ...this.querySelectorAll('option'),
186
+ ]),
187
+ ].filter(x => !!x);
188
+ }
189
+ render() {
190
+ return html `
191
+ <div id="toggle">
192
+ <input id="combobox">
193
+ <button id="button">Show Options</button>
194
+ </div>
195
+ <div id="listbox">
196
+ <option id="placeholder" aria-disabled="true">Select an Option</option>
197
+ ${this.controller.renderItemsToShadowRoot()}
198
+ <div ?hidden=${!ComboboxController.supportsCrossRootActiveDescendant}>
199
+ <slot></slot>
200
+ </div>
201
+ </div>
202
+ `;
203
+ }
204
+ };
205
+ XComboboxCrossRoot.template = html `
206
+ <x-combobox-cross-root>
207
+ <option>1</option>
208
+ <option>2</option>
209
+ <option>3</option>
210
+ <option>4</option>
211
+ <option>5</option>
212
+ <option>6</option>
213
+ <option>7</option>
214
+ <option>8</option>
215
+ <option>9</option>
216
+ <option>10</option>
217
+ </x-combobox-cross-root>
218
+ `;
219
+ XComboboxCrossRoot = __decorate([
220
+ customElement('x-combobox-cross-root')
221
+ ], XComboboxCrossRoot);
222
+ let XComboboxLight = class XComboboxLight extends TestCombobox {
223
+ createRenderRoot() {
224
+ return this;
225
+ }
226
+ render() {
227
+ return html `
228
+ <input id="combobox">
229
+ <button id="button">Show Options</button>
230
+ <div id="listbox">
231
+ <option id="placeholder" aria-disabled="true">Select an Option</option>
232
+ <option>1</option>
233
+ <option>2</option>
234
+ <option>3</option>
235
+ <option>4</option>
236
+ <option>5</option>
237
+ <option>6</option>
238
+ <option>7</option>
239
+ <option>8</option>
240
+ <option>9</option>
241
+ <option>10</option>
242
+ </div>`;
243
+ }
244
+ };
245
+ XComboboxLight.template = html `
246
+ <x-combobox-light></x-combobox-light>
247
+ `;
248
+ XComboboxLight = __decorate([
249
+ customElement('x-combobox-light')
250
+ ], XComboboxLight);
251
+ let XComboboxShadow = class XComboboxShadow extends TestCombobox {
252
+ render() {
253
+ return html `
254
+ <input id="combobox">
255
+ <button id="button">Show Options</button>
256
+ <div id="listbox">
257
+ <option id="placeholder" aria-disabled="true">Select an Option</option>
258
+ <option>1</option>
259
+ <option>2</option>
260
+ <option>3</option>
261
+ <option>4</option>
262
+ <option>5</option>
263
+ <option>6</option>
264
+ <option>7</option>
265
+ <option>8</option>
266
+ <option>9</option>
267
+ <option>10</option>
268
+ </div>`;
269
+ }
270
+ };
271
+ XComboboxShadow.template = html `
272
+ <x-combobox-shadow></x-combobox-shadow>
273
+ `;
274
+ XComboboxShadow = __decorate([
275
+ customElement('x-combobox-shadow')
276
+ ], XComboboxShadow);
277
+ describe('ComboboxController', function () {
278
+ describe('Cross-root ARIA', XComboboxCrossRoot.test.bind(XComboboxCrossRoot));
279
+ describe('Light-DOM only', XComboboxLight.test.bind(XComboboxLight));
280
+ describe('Shadow-DOM only', XComboboxShadow.test.bind(XComboboxShadow));
281
+ });
282
+ //# sourceMappingURL=combobox-controller.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combobox-controller.spec.js","sourceRoot":"","sources":["combobox-controller.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, nextFrame } from '@open-wc/testing';\nimport { sendKeys } from '@web/test-runner-commands';\nimport { a11ySnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js';\n\nimport { customElement } from 'lit/decorators/custom-element.js';\nimport { query } from 'lit/decorators/query.js';\nimport { ReactiveElement, html, render, type PropertyValues, type TemplateResult } from 'lit';\n\nimport { ComboboxController } from '../combobox-controller.js';\n\nfunction press(key: string) {\n return async function() {\n await sendKeys({ press: key });\n };\n}\n\nabstract class TestCombobox extends ReactiveElement {\n declare static template: TemplateResult;\n\n static styles = new CSSStyleSheet();\n\n static {\n this.styles.replaceSync(/* css */`\n option {\n &.active {\n outline: 1px solid black;\n }\n &[selected] {\n background: lightblue;\n }\n }\n `);\n }\n\n controller = ComboboxController.of(this, {\n multi: false,\n getItems: () => this.options,\n isItem: item => item instanceof HTMLOptionElement,\n getFallbackLabel: () => 'options',\n getListboxElement: () => this.listbox ?? null,\n getToggleButton: () => this.button ?? null,\n getComboboxInput: () => this.combobox ?? null,\n isExpanded: () => !this.listbox.hidden,\n requestShowListbox: () => void (this.listbox.hidden = false),\n requestHideListbox: () => void (this.listbox.hidden = true),\n setItemActive: (item, active) => item.classList.toggle('active', active),\n setItemSelected: (item, selected) => item.selected = selected,\n });\n\n @query('#listbox') listbox!: HTMLElement;\n @query('#button') button!: HTMLButtonElement;\n @query('#combobox') combobox!: HTMLInputElement;\n @query('#placeholder') placeholder!: HTMLOptionElement;\n\n /** List of options */\n get options(): HTMLOptionElement[] {\n return [\n ...new Set([\n this.placeholder,\n ...this.querySelectorAll('option'),\n ...this.renderRoot.querySelectorAll('option'),\n ]),\n ].filter(x => !!x);\n }\n\n get selected() {\n return this.options.filter(x => x.selected);\n }\n\n get activeOption() {\n return this.options.find(x => x.classList.contains('active'));\n }\n\n abstract render(): TemplateResult;\n\n override update(changed: PropertyValues<this>) {\n render(this.render(), this.renderRoot);\n super.update(changed);\n this.placeholder.inert = !!this.controller.selected.length;\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n const root = this.renderRoot.getRootNode() as Document | ShadowRoot;\n root.adoptedStyleSheets = [...root.adoptedStyleSheets ?? [], TestCombobox.styles];\n }\n\n static async test() {\n let element: TestCombobox;\n\n const updateComplete = () => element.updateComplete;\n\n const { template } = this;\n\n if (!template) {\n throw new Error(`${this.constructor.name} must implement template`);\n }\n\n beforeEach(async function() {\n element = await fixture<TestCombobox>(template);\n });\n\n describe('Tab', function() {\n beforeEach(press('Tab'));\n beforeEach(updateComplete);\n\n it('focuses the combobox', async function() {\n expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');\n });\n\n describe('Tab', function() {\n beforeEach(press('Tab'));\n beforeEach(updateComplete);\n beforeEach(nextFrame);\n\n it('does not focus the toggle button', async function() {\n expect(await a11ySnapshot()).to.not.axContainQuery({ focused: true });\n });\n });\n\n describe('ArrowDown', function() {\n beforeEach(press('ArrowDown'));\n beforeEach(updateComplete);\n\n it('expands the listbox', async function() {\n expect(await a11ySnapshot())\n .to.axContainRole('listbox')\n .and\n .to.axContainQuery({ role: 'combobox', expanded: true });\n });\n\n it('maintains DOM focus on the combobox', async function() {\n expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');\n });\n\n it('sets active state on the placeholder', function() {\n expect(element.activeOption).to.equal(element.placeholder);\n });\n\n describe('Enter', function() {\n beforeEach(press('Enter'));\n beforeEach(updateComplete);\n\n it('maintains DOM focus on the combobox', async function() {\n expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');\n });\n\n it('selects nothing', function() {\n expect(element.selected).to.have.length(0);\n });\n });\n\n describe('ArrowDown', function() {\n beforeEach(press('ArrowDown'));\n beforeEach(updateComplete);\n\n it('maintains DOM focus on the combobox', async function() {\n expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');\n });\n\n it('sets active state on the 1st option', function() {\n expect(element.activeOption).to.have.text('1');\n });\n\n describe('Enter', function() {\n beforeEach(press('Enter'));\n beforeEach(updateComplete);\n\n it('maintains DOM focus on the combobox', async function() {\n expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');\n });\n\n it('selects the first option', function() {\n expect(element.selected).to.have.length(1);\n expect(element.selected.at(0)).to.have.text('1');\n });\n\n it('collapses the listbox', async function() {\n expect(await a11ySnapshot())\n .to.not.axContainRole('listbox')\n .and\n .to.axContainQuery({ role: 'combobox', expanded: false });\n });\n });\n });\n\n describe('Escape', function() {\n beforeEach(press('Escape'));\n beforeEach(updateComplete);\n\n it('collapses the listbox', async function() {\n expect(await a11ySnapshot())\n .to.not.axContainRole('listbox')\n .and\n .to.axContainQuery({ role: 'combobox', expanded: false });\n });\n\n it('maintains DOM focus on the combobox', async function() {\n expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');\n });\n });\n });\n });\n };\n}\n\n@customElement('x-combobox-cross-root')\nclass XComboboxCrossRoot extends TestCombobox {\n static template = html`\n <x-combobox-cross-root>\n <option>1</option>\n <option>2</option>\n <option>3</option>\n <option>4</option>\n <option>5</option>\n <option>6</option>\n <option>7</option>\n <option>8</option>\n <option>9</option>\n <option>10</option>\n </x-combobox-cross-root>\n `;\n\n\n /** List of options */\n override get options(): HTMLOptionElement[] {\n return [\n ...new Set([\n this.placeholder,\n ...this.querySelectorAll('option'),\n ]),\n ].filter(x => !!x);\n }\n\n render() {\n return html`\n <div id=\"toggle\">\n <input id=\"combobox\">\n <button id=\"button\">Show Options</button>\n </div>\n <div id=\"listbox\">\n <option id=\"placeholder\" aria-disabled=\"true\">Select an Option</option>\n ${this.controller.renderItemsToShadowRoot()}\n <div ?hidden=${!ComboboxController.supportsCrossRootActiveDescendant}>\n <slot></slot>\n </div>\n </div>\n `;\n }\n}\n\n@customElement('x-combobox-light')\nclass XComboboxLight extends TestCombobox {\n static template = html`\n <x-combobox-light></x-combobox-light>\n `;\n\n protected createRenderRoot(): HTMLElement | DocumentFragment {\n return this;\n }\n\n render() {\n return html`\n <input id=\"combobox\">\n <button id=\"button\">Show Options</button>\n <div id=\"listbox\">\n <option id=\"placeholder\" aria-disabled=\"true\">Select an Option</option>\n <option>1</option>\n <option>2</option>\n <option>3</option>\n <option>4</option>\n <option>5</option>\n <option>6</option>\n <option>7</option>\n <option>8</option>\n <option>9</option>\n <option>10</option>\n </div>`;\n }\n}\n\n@customElement('x-combobox-shadow')\nclass XComboboxShadow extends TestCombobox {\n static template = html`\n <x-combobox-shadow></x-combobox-shadow>\n `;\n\n render() {\n return html`\n <input id=\"combobox\">\n <button id=\"button\">Show Options</button>\n <div id=\"listbox\">\n <option id=\"placeholder\" aria-disabled=\"true\">Select an Option</option>\n <option>1</option>\n <option>2</option>\n <option>3</option>\n <option>4</option>\n <option>5</option>\n <option>6</option>\n <option>7</option>\n <option>8</option>\n <option>9</option>\n <option>10</option>\n </div>`;\n }\n}\n\ndescribe('ComboboxController', function() {\n describe('Cross-root ARIA', XComboboxCrossRoot.test.bind(XComboboxCrossRoot));\n describe('Light-DOM only', XComboboxLight.test.bind(XComboboxLight));\n describe('Shadow-DOM only', XComboboxShadow.test.bind(XComboboxShadow));\n});\n"]}
@@ -28,7 +28,8 @@ export class TimestampController {
28
28
  return __classPrivateFieldGet(this, _TimestampController_instances, "m", _TimestampController_getTimeRelative).call(this);
29
29
  }
30
30
  else {
31
- let { displaySuffix, locale } = __classPrivateFieldGet(this, _TimestampController_options, "f");
31
+ let { displaySuffix } = __classPrivateFieldGet(this, _TimestampController_options, "f");
32
+ const { locale } = __classPrivateFieldGet(this, _TimestampController_options, "f");
32
33
  if (__classPrivateFieldGet(this, _TimestampController_options, "f").utc) {
33
34
  displaySuffix || (displaySuffix = 'UTC');
34
35
  }
@@ -66,7 +67,11 @@ _a = TimestampController, _TimestampController_date = new WeakMap(), _TimestampC
66
67
  }, _TimestampController_getTimeRelative = function _TimestampController_getTimeRelative() {
67
68
  const date = __classPrivateFieldGet(this, _TimestampController_date, "f");
68
69
  const { locale } = __classPrivateFieldGet(this, _TimestampController_options, "f");
69
- const rtf = new Intl.RelativeTimeFormat(locale, { localeMatcher: 'best fit', numeric: 'auto', style: 'long' });
70
+ const rtf = new Intl.RelativeTimeFormat(locale, {
71
+ localeMatcher: 'best fit',
72
+ numeric: 'auto',
73
+ style: 'long',
74
+ });
70
75
  const ms = date.getTime() - Date.now();
71
76
  const tense = ms > 0 ? 1 : -1;
72
77
  let qty = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"timestamp-controller.js","sourceRoot":"","sources":["timestamp-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nexport type DateTimeFormat = 'full' | 'long' | 'medium' | 'short';\n\nexport interface TimestampOptions {\n dateFormat?: DateTimeFormat;\n timeFormat?: DateTimeFormat;\n customFormat?: Intl.DateTimeFormatOptions;\n displaySuffix: string;\n locale: Intl.LocalesArgument;\n relative: boolean;\n utc: boolean;\n hour12: boolean;\n}\n\nconst defaults = {\n dateFormat: undefined,\n timeFormat: undefined,\n customFormat: undefined,\n displaySuffix: '',\n locale: undefined,\n relative: false,\n utc: false,\n hour12: false,\n} as const;\n\nexport class TimestampController implements ReactiveController {\n static #isTimestampOptionKey(prop: PropertyKey): prop is keyof TimestampOptions {\n return prop in defaults;\n }\n\n #date = new Date();\n\n #options: TimestampOptions = {} as TimestampOptions;\n\n #host: ReactiveControllerHost;\n\n get localeString() {\n return this.#date.toLocaleString(this.#options.locale);\n }\n\n get date() {\n return this.#date;\n }\n\n set date(string) {\n this.#date = new Date(string);\n }\n\n get isoString() {\n return this.#date.toISOString();\n }\n\n get time() {\n if (this.#options.relative) {\n return this.#getTimeRelative();\n } else {\n let { displaySuffix, locale } = this.#options;\n if (this.#options.utc) {\n displaySuffix ||= 'UTC';\n }\n const localeString = this.#date.toLocaleString(locale, this.#options.customFormat ?? {\n hour12: this.#options.hour12,\n timeStyle: this.#options.timeFormat,\n dateStyle: this.#options.dateFormat,\n ...this.#options.utc && { timeZone: 'UTC' },\n });\n\n return `${localeString} ${displaySuffix ?? ''}`.trim();\n }\n }\n\n constructor(host: ReactiveControllerHost, options?: Partial<TimestampOptions>) {\n this.#host = host;\n host.addController(this);\n for (const [name, value] of Object.entries(this.#options)) {\n // @ts-expect-error: seems typescript compiler isn't up to the task here\n this.#options[name] = options?.[name] ?? value;\n }\n }\n\n hostConnected?(): void\n\n /**\n * Based off of Github Relative Time\n * https://github.com/github/time-elements/blob/master/src/relative-time.js\n */\n #getTimeRelative() {\n const date = this.#date;\n const { locale } = this.#options;\n const rtf = new Intl.RelativeTimeFormat(locale as string, { localeMatcher: 'best fit', numeric: 'auto', style: 'long' });\n const ms: number = date.getTime() - Date.now();\n const tense = ms > 0 ? 1 : -1;\n let qty = 0;\n let units: Intl.RelativeTimeFormatUnit | undefined;\n const s = Math.round(Math.abs(ms) / 1000);\n const min = Math.round(s / 60);\n const h = Math.round(min / 60);\n const d = Math.round(h / 24);\n const m = Math.round(d / 30);\n const y = Math.round(m / 12);\n if (m >= 12) {\n qty = y;\n units = 'year';\n } else if (d >= 30) {\n qty = m;\n units = 'month';\n } else if (h >= 24) {\n qty = d;\n units = 'day';\n } else if (min >= 45) {\n qty = h;\n units = 'hour';\n } else if (s >= 45) {\n qty = min;\n units = 'minute';\n } else if (s >= 10) {\n qty = s;\n units = 'second';\n }\n\n return typeof (units) !== 'undefined' ? rtf.format(tense * qty, units) : 'just now';\n }\n\n set(prop: PropertyKey, value: unknown) {\n if (TimestampController.#isTimestampOptionKey(prop)) {\n // @ts-expect-error: seems typescript compiler isn't up to the task here\n this.#options[prop] = value;\n this.#host.requestUpdate();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"timestamp-controller.js","sourceRoot":"","sources":["timestamp-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nexport type DateTimeFormat = 'full' | 'long' | 'medium' | 'short';\n\nexport interface TimestampOptions {\n dateFormat?: DateTimeFormat;\n timeFormat?: DateTimeFormat;\n customFormat?: Intl.DateTimeFormatOptions;\n displaySuffix: string;\n locale: Intl.LocalesArgument;\n relative: boolean;\n utc: boolean;\n hour12: boolean;\n}\n\nconst defaults = {\n dateFormat: undefined,\n timeFormat: undefined,\n customFormat: undefined,\n displaySuffix: '',\n locale: undefined,\n relative: false,\n utc: false,\n hour12: false,\n} as const;\n\nexport class TimestampController implements ReactiveController {\n static #isTimestampOptionKey(prop: PropertyKey): prop is keyof TimestampOptions {\n return prop in defaults;\n }\n\n #date = new Date();\n\n #options: TimestampOptions = {} as TimestampOptions;\n\n #host: ReactiveControllerHost;\n\n get localeString(): string {\n return this.#date.toLocaleString(this.#options.locale);\n }\n\n get date(): Date {\n return this.#date;\n }\n\n set date(string) {\n this.#date = new Date(string);\n }\n\n get isoString(): string {\n return this.#date.toISOString();\n }\n\n get time(): string {\n if (this.#options.relative) {\n return this.#getTimeRelative();\n } else {\n let { displaySuffix } = this.#options;\n const { locale } = this.#options;\n if (this.#options.utc) {\n displaySuffix ||= 'UTC';\n }\n const localeString = this.#date.toLocaleString(locale, this.#options.customFormat ?? {\n hour12: this.#options.hour12,\n timeStyle: this.#options.timeFormat,\n dateStyle: this.#options.dateFormat,\n ...this.#options.utc && { timeZone: 'UTC' },\n });\n\n return `${localeString} ${displaySuffix ?? ''}`.trim();\n }\n }\n\n constructor(host: ReactiveControllerHost, options?: Partial<TimestampOptions>) {\n this.#host = host;\n host.addController(this);\n for (const [name, value] of Object.entries(this.#options)) {\n // @ts-expect-error: seems typescript compiler isn't up to the task here\n this.#options[name] = options?.[name] ?? value;\n }\n }\n\n hostConnected?(): void;\n\n /**\n * Based off of Github Relative Time\n * https://github.com/github/time-elements/blob/master/src/relative-time.js\n */\n #getTimeRelative() {\n const date = this.#date;\n const { locale } = this.#options;\n const rtf = new Intl.RelativeTimeFormat(locale as string, {\n localeMatcher: 'best fit',\n numeric: 'auto',\n style: 'long',\n });\n const ms: number = date.getTime() - Date.now();\n const tense = ms > 0 ? 1 : -1;\n let qty = 0;\n let units: Intl.RelativeTimeFormatUnit | undefined;\n const s = Math.round(Math.abs(ms) / 1000);\n const min = Math.round(s / 60);\n const h = Math.round(min / 60);\n const d = Math.round(h / 24);\n const m = Math.round(d / 30);\n const y = Math.round(m / 12);\n if (m >= 12) {\n qty = y;\n units = 'year';\n } else if (d >= 30) {\n qty = m;\n units = 'month';\n } else if (h >= 24) {\n qty = d;\n units = 'day';\n } else if (min >= 45) {\n qty = h;\n units = 'hour';\n } else if (s >= 45) {\n qty = min;\n units = 'minute';\n } else if (s >= 10) {\n qty = s;\n units = 'second';\n }\n\n return typeof (units) !== 'undefined' ? rtf.format(tense * qty, units) : 'just now';\n }\n\n set(prop: PropertyKey, value: unknown): void {\n if (TimestampController.#isTimestampOptionKey(prop)) {\n // @ts-expect-error: seems typescript compiler isn't up to the task here\n this.#options[prop] = value;\n this.#host.requestUpdate();\n }\n }\n}\n"]}