You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

635 lines
21 KiB

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.PFElement = factory());
  5. }(this, (function () { 'use strict';
  6. var logger = function logger() {
  7. return null;
  8. };
  9. function reveal() {
  10. logger("[reveal] elements ready, revealing the body");
  11. window.document.body.removeAttribute("unresolved");
  12. }
  13. function autoReveal(logFunction) {
  14. logger = logFunction;
  15. // If Web Components are already ready, run the handler right away. If they
  16. // are not yet ready, wait.
  17. //
  18. // see https://github.com/github/webcomponentsjs#webcomponents-loaderjs for
  19. // info about web component readiness events
  20. var polyfillPresent = window.WebComponents;
  21. var polyfillReady = polyfillPresent && window.WebComponents.ready;
  22. if (!polyfillPresent || polyfillReady) {
  23. handleWebComponentsReady();
  24. } else {
  25. window.addEventListener("WebComponentsReady", handleWebComponentsReady);
  26. }
  27. }
  28. function handleWebComponentsReady() {
  29. logger("[reveal] web components ready");
  30. reveal();
  31. }
  32. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  33. return typeof obj;
  34. } : function (obj) {
  35. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  36. };
  37. var classCallCheck = function (instance, Constructor) {
  38. if (!(instance instanceof Constructor)) {
  39. throw new TypeError("Cannot call a class as a function");
  40. }
  41. };
  42. var createClass = function () {
  43. function defineProperties(target, props) {
  44. for (var i = 0; i < props.length; i++) {
  45. var descriptor = props[i];
  46. descriptor.enumerable = descriptor.enumerable || false;
  47. descriptor.configurable = true;
  48. if ("value" in descriptor) descriptor.writable = true;
  49. Object.defineProperty(target, descriptor.key, descriptor);
  50. }
  51. }
  52. return function (Constructor, protoProps, staticProps) {
  53. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  54. if (staticProps) defineProperties(Constructor, staticProps);
  55. return Constructor;
  56. };
  57. }();
  58. var inherits = function (subClass, superClass) {
  59. if (typeof superClass !== "function" && superClass !== null) {
  60. throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
  61. }
  62. subClass.prototype = Object.create(superClass && superClass.prototype, {
  63. constructor: {
  64. value: subClass,
  65. enumerable: false,
  66. writable: true,
  67. configurable: true
  68. }
  69. });
  70. if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
  71. };
  72. var possibleConstructorReturn = function (self, call) {
  73. if (!self) {
  74. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  75. }
  76. return call && (typeof call === "object" || typeof call === "function") ? call : self;
  77. };
  78. var toConsumableArray = function (arr) {
  79. if (Array.isArray(arr)) {
  80. for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
  81. return arr2;
  82. } else {
  83. return Array.from(arr);
  84. }
  85. };
  86. /*!
  87. * PatternFly Elements: PFElement 1.0.0-prerelease.55
  88. * @license
  89. * Copyright 2020 Red Hat, Inc.
  90. *
  91. * Permission is hereby granted, free of charge, to any person obtaining a copy
  92. * of this software and associated documentation files (the "Software"), to deal
  93. * in the Software without restriction, including without limitation the rights
  94. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  95. * copies of the Software, and to permit persons to whom the Software is
  96. * furnished to do so, subject to the following conditions:
  97. *
  98. * The above copyright notice and this permission notice shall be included in
  99. * all copies or substantial portions of the Software.
  100. *
  101. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  102. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  103. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  104. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  105. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  106. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  107. * SOFTWARE.
  108. *
  109. */
  110. var prefix = "pfe-";
  111. var PFElement = function (_HTMLElement) {
  112. inherits(PFElement, _HTMLElement);
  113. createClass(PFElement, [{
  114. key: "cssVariable",
  115. value: function cssVariable(name, value) {
  116. var element = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this;
  117. name = name.substr(0, 2) !== "--" ? "--" + name : name;
  118. if (value) {
  119. element.style.setProperty(name, value);
  120. }
  121. return window.getComputedStyle(element).getPropertyValue(name).trim();
  122. }
  123. // Returns a single element assigned to that slot; if multiple, it returns the first
  124. }, {
  125. key: "has_slot",
  126. value: function has_slot(name) {
  127. return this.querySelector("[slot='" + name + "']");
  128. }
  129. // Returns an array with all elements assigned to that slot
  130. }, {
  131. key: "has_slots",
  132. value: function has_slots(name) {
  133. return [].concat(toConsumableArray(this.querySelectorAll("[slot='" + name + "']")));
  134. }
  135. // Update the theme context for self and children
  136. }, {
  137. key: "context_update",
  138. value: function context_update() {
  139. // TODO: update this to use :defined?
  140. var children = this.querySelectorAll("[pfelement]");
  141. var theme = this.cssVariable("theme");
  142. // Manually adding `pfe-theme` overrides the css variable
  143. if (this.hasAttribute("pfe-theme")) {
  144. theme = this.getAttribute("pfe-theme");
  145. // Update the css variable to match the data attribute
  146. this.cssVariable("theme", theme);
  147. }
  148. // Update theme for self
  149. this.context_set(theme);
  150. // For each nested, already upgraded component
  151. // set the context based on the child's value of --theme
  152. // Note: this prevents contexts from parents overriding
  153. // the child's context should it exist
  154. [].concat(toConsumableArray(children)).map(function (child) {
  155. if (child.connected) {
  156. child.context_set(theme);
  157. }
  158. });
  159. }
  160. // Get the theme variable if it exists, set it as an attribute
  161. }, {
  162. key: "context_set",
  163. value: function context_set(fallback) {
  164. var theme = this.cssVariable("theme");
  165. if (!theme) {
  166. theme = this.getAttribute("pfe-theme");
  167. }
  168. if (!theme && fallback) {
  169. theme = fallback;
  170. }
  171. if (theme && this.hasAttribute("pfelement")) {
  172. this.setAttribute("on", theme);
  173. }
  174. }
  175. }, {
  176. key: "randomId",
  177. get: function get$$1() {
  178. return "pfe-" + Math.random().toString(36).substr(2, 9);
  179. }
  180. }, {
  181. key: "version",
  182. get: function get$$1() {
  183. return this._pfeClass.version;
  184. }
  185. }, {
  186. key: "pfeType",
  187. get: function get$$1() {
  188. return this.getAttribute(prefix + "type");
  189. },
  190. set: function set$$1(value) {
  191. this.setAttribute(prefix + "type", value);
  192. }
  193. }], [{
  194. key: "create",
  195. value: function create(pfe) {
  196. window.customElements.define(pfe.tag, pfe);
  197. }
  198. }, {
  199. key: "debugLog",
  200. value: function debugLog() {
  201. var preference = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
  202. if (preference !== null) {
  203. PFElement._debugLog = !!preference;
  204. }
  205. return PFElement._debugLog;
  206. }
  207. }, {
  208. key: "log",
  209. value: function log() {
  210. if (PFElement.debugLog()) {
  211. var _console;
  212. (_console = console).log.apply(_console, arguments);
  213. }
  214. }
  215. }, {
  216. key: "PfeTypes",
  217. get: function get$$1() {
  218. return {
  219. Container: "container",
  220. Content: "content",
  221. Combo: "combo"
  222. };
  223. }
  224. }, {
  225. key: "version",
  226. get: function get$$1() {
  227. return "{{version}}";
  228. }
  229. }, {
  230. key: "observedAttributes",
  231. get: function get$$1() {
  232. return ["pfe-theme"];
  233. }
  234. }]);
  235. function PFElement(pfeClass) {
  236. var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
  237. _ref$type = _ref.type,
  238. type = _ref$type === undefined ? null : _ref$type,
  239. _ref$delayRender = _ref.delayRender,
  240. delayRender = _ref$delayRender === undefined ? false : _ref$delayRender;
  241. classCallCheck(this, PFElement);
  242. var _this = possibleConstructorReturn(this, (PFElement.__proto__ || Object.getPrototypeOf(PFElement)).call(this));
  243. _this.connected = false;
  244. _this._pfeClass = pfeClass;
  245. _this.tag = pfeClass.tag;
  246. _this.props = pfeClass.properties;
  247. _this.slots = pfeClass.slots;
  248. _this._queue = [];
  249. _this.template = document.createElement("template");
  250. _this.log("Constructing...");
  251. _this.attachShadow({ mode: "open" });
  252. if (type) {
  253. _this._queueAction({
  254. type: "setProperty",
  255. data: {
  256. name: "pfeType",
  257. value: type
  258. }
  259. });
  260. }
  261. if (!delayRender) {
  262. _this.log("Render...");
  263. _this.render();
  264. _this.log("Rendered.");
  265. }
  266. _this.log("Constructed.");
  267. return _this;
  268. }
  269. createClass(PFElement, [{
  270. key: "connectedCallback",
  271. value: function connectedCallback() {
  272. this.connected = true;
  273. this.log("Connecting...");
  274. if (window.ShadyCSS) {
  275. this.log("Styling...");
  276. window.ShadyCSS.styleElement(this);
  277. this.log("Styled.");
  278. }
  279. // Throw a warning if the on attribute was manually added before upgrade
  280. if (!this.hasAttribute("pfelement") && this.hasAttribute("on")) {
  281. console.warn("" + this.tag + (this.id ? "[#" + this.id + "]" : "") + ": The \"on\" attribute is protected and should not be manually added to a component. The base class will manage this value for you on upgrade.");
  282. }
  283. // @TODO maybe we should use just the attribute instead of the class?
  284. // https://github.com/angular/angular/issues/15399#issuecomment-318785677
  285. this.classList.add("PFElement");
  286. this.setAttribute("pfelement", "");
  287. if (_typeof(this.props) === "object") {
  288. this._mapSchemaToProperties(this.tag, this.props);
  289. this.log("Properties attached.");
  290. }
  291. if (_typeof(this.slots) === "object") {
  292. this._mapSchemaToSlots(this.tag, this.slots);
  293. this.log("Slots attached.");
  294. }
  295. if (this._queue.length) {
  296. this._processQueue();
  297. }
  298. // Initialize the on attribute if a theme variable is set
  299. // do not update the on attribute if a user has manually added it
  300. // then trigger an update in nested components
  301. this.context_update();
  302. this.log("Connected.");
  303. }
  304. }, {
  305. key: "disconnectedCallback",
  306. value: function disconnectedCallback() {
  307. this.log("Disconnecting...");
  308. this.connected = false;
  309. this.log("Disconnected.");
  310. }
  311. }, {
  312. key: "attributeChangedCallback",
  313. value: function attributeChangedCallback(attr, oldVal, newVal) {
  314. if (!this._pfeClass.cascadingAttributes) {
  315. return;
  316. }
  317. var cascadeTo = this._pfeClass.cascadingAttributes[attr];
  318. if (cascadeTo) {
  319. this._copyAttribute(attr, cascadeTo);
  320. }
  321. if (attr === "pfe-theme") {
  322. this.context_update();
  323. }
  324. }
  325. }, {
  326. key: "_copyAttribute",
  327. value: function _copyAttribute(name, to) {
  328. var recipients = [].concat(toConsumableArray(this.querySelectorAll(to)), toConsumableArray(this.shadowRoot.querySelectorAll(to)));
  329. var value = this.getAttribute(name);
  330. var fname = value == null ? "removeAttribute" : "setAttribute";
  331. var _iteratorNormalCompletion = true;
  332. var _didIteratorError = false;
  333. var _iteratorError = undefined;
  334. try {
  335. for (var _iterator = recipients[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  336. var node = _step.value;
  337. node[fname](name, value);
  338. }
  339. } catch (err) {
  340. _didIteratorError = true;
  341. _iteratorError = err;
  342. } finally {
  343. try {
  344. if (!_iteratorNormalCompletion && _iterator.return) {
  345. _iterator.return();
  346. }
  347. } finally {
  348. if (_didIteratorError) {
  349. throw _iteratorError;
  350. }
  351. }
  352. }
  353. }
  354. // Map the imported properties json to real props on the element
  355. // @notice static getter of properties is built via tooling
  356. // to edit modify src/element.json
  357. }, {
  358. key: "_mapSchemaToProperties",
  359. value: function _mapSchemaToProperties(tag, properties) {
  360. var _this2 = this;
  361. this.log("Mapping properties...");
  362. // Loop over the properties provided by the schema
  363. Object.keys(properties).forEach(function (attr) {
  364. var data = properties[attr];
  365. // Only attach the information if the data provided is a schema object
  366. if ((typeof data === "undefined" ? "undefined" : _typeof(data)) === "object") {
  367. // Prefix default is true
  368. var hasPrefix = true;
  369. var attrName = attr;
  370. // Set the attribute's property equal to the schema input
  371. _this2[attr] = data;
  372. // Initialize the value to null
  373. _this2[attr].value = null;
  374. if (typeof _this2[attr].prefixed !== "undefined") {
  375. hasPrefix = _this2[attr].prefixed;
  376. }
  377. if (hasPrefix) {
  378. attrName = "" + prefix + attr;
  379. }
  380. // If the attribute exists on the host
  381. if (_this2.hasAttribute(attrName)) {
  382. // Set property value based on the existing attribute
  383. _this2[attr].value = _this2.getAttribute(attrName);
  384. }
  385. // Otherwise, look for a default and use that instead
  386. else if (data.default) {
  387. var dependency_exists = _this2._hasDependency(tag, data.options);
  388. var no_dependencies = !data.options || data.options && !data.options.dependencies.length;
  389. // If the dependency exists or there are no dependencies, set the default
  390. if (dependency_exists || no_dependencies) {
  391. _this2.setAttribute(attrName, data.default);
  392. _this2[attr].value = data.default;
  393. }
  394. }
  395. }
  396. });
  397. this.log("Properties mapped.");
  398. }
  399. // Test whether expected dependencies exist
  400. }, {
  401. key: "_hasDependency",
  402. value: function _hasDependency(tag, opts) {
  403. // Get any possible dependencies for this attribute to exist
  404. var dependencies = opts ? opts.dependencies : [];
  405. // Initialize the dependency return value
  406. var hasDependency = false;
  407. // Check that dependent item exists
  408. // Loop through the dependencies defined
  409. for (var i = 0; i < dependencies.length; i += 1) {
  410. var slot_exists = dependencies[i].type === "slot" && this.has_slots(tag + "--" + dependencies[i].id).length > 0;
  411. var attribute_exists = dependencies[i].type === "attribute" && this.getAttribute("" + prefix + dependencies[i].id);
  412. // If the type is slot, check that it exists OR
  413. // if the type is an attribute, check if the attribute is defined
  414. if (slot_exists || attribute_exists) {
  415. // If the slot does exist, add the attribute with the default value
  416. hasDependency = true;
  417. // Exit the loop
  418. break;
  419. }
  420. }
  421. // Return a boolean if the dependency exists
  422. return hasDependency;
  423. }
  424. // Map the imported slots json
  425. // @notice static getter of properties is built via tooling
  426. // to edit modify src/element.json
  427. }, {
  428. key: "_mapSchemaToSlots",
  429. value: function _mapSchemaToSlots(tag, slots) {
  430. var _this3 = this;
  431. this.log("Validate slots...");
  432. // Loop over the properties provided by the schema
  433. Object.keys(slots).forEach(function (slot) {
  434. var slotObj = slots[slot];
  435. // Only attach the information if the data provided is a schema object
  436. if ((typeof slotObj === "undefined" ? "undefined" : _typeof(slotObj)) === "object") {
  437. var slotExists = false;
  438. var result = [];
  439. // If it's a named slot, look for that slot definition
  440. if (slotObj.namedSlot) {
  441. // Check prefixed slots
  442. result = _this3.has_slots(tag + "--" + slot);
  443. if (result.length > 0) {
  444. slotObj.nodes = result;
  445. slotExists = true;
  446. }
  447. // Check for unprefixed slots
  448. result = _this3.has_slots("" + slot);
  449. if (result.length > 0) {
  450. slotObj.nodes = result;
  451. slotExists = true;
  452. }
  453. // If it's the default slot, look for direct children not assigned to a slot
  454. } else {
  455. result = [].concat(toConsumableArray(_this3.children)).filter(function (child) {
  456. return !child.hasAttribute("slot");
  457. });
  458. if (result.length > 0) {
  459. slotObj.nodes = result;
  460. slotExists = true;
  461. }
  462. }
  463. // If the slot exists, attach an attribute to the parent to indicate that
  464. if (slotExists) {
  465. _this3.setAttribute("has_" + slot, "");
  466. } else {
  467. _this3.removeAttribute("has_" + slot);
  468. }
  469. }
  470. });
  471. this.log("Slots validated.");
  472. }
  473. }, {
  474. key: "_queueAction",
  475. value: function _queueAction(action) {
  476. this._queue.push(action);
  477. }
  478. }, {
  479. key: "_processQueue",
  480. value: function _processQueue() {
  481. var _this4 = this;
  482. this._queue.forEach(function (action) {
  483. _this4["_" + action.type](action.data);
  484. });
  485. this._queue = [];
  486. }
  487. }, {
  488. key: "_setProperty",
  489. value: function _setProperty(_ref2) {
  490. var name = _ref2.name,
  491. value = _ref2.value;
  492. this[name] = value;
  493. }
  494. // @TODO This is a duplicate function to cssVariable above, combine them
  495. }, {
  496. key: "var",
  497. value: function _var(name) {
  498. return PFElement.var(name, this);
  499. }
  500. }, {
  501. key: "render",
  502. value: function render() {
  503. this.shadowRoot.innerHTML = "";
  504. this.template.innerHTML = this.html;
  505. if (window.ShadyCSS) {
  506. window.ShadyCSS.prepareTemplate(this.template, this.tag);
  507. }
  508. this.shadowRoot.appendChild(this.template.content.cloneNode(true));
  509. }
  510. }, {
  511. key: "log",
  512. value: function log() {
  513. for (var _len = arguments.length, msgs = Array(_len), _key = 0; _key < _len; _key++) {
  514. msgs[_key] = arguments[_key];
  515. }
  516. PFElement.log.apply(PFElement, ["[" + this.tag + "]"].concat(msgs));
  517. }
  518. }, {
  519. key: "emitEvent",
  520. value: function emitEvent(name) {
  521. var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
  522. _ref3$bubbles = _ref3.bubbles,
  523. bubbles = _ref3$bubbles === undefined ? true : _ref3$bubbles,
  524. _ref3$cancelable = _ref3.cancelable,
  525. cancelable = _ref3$cancelable === undefined ? false : _ref3$cancelable,
  526. _ref3$composed = _ref3.composed,
  527. composed = _ref3$composed === undefined ? false : _ref3$composed,
  528. _ref3$detail = _ref3.detail,
  529. detail = _ref3$detail === undefined ? {} : _ref3$detail;
  530. this.log("Custom event: " + name);
  531. this.dispatchEvent(new CustomEvent(name, {
  532. bubbles: bubbles,
  533. cancelable: cancelable,
  534. composed: composed,
  535. detail: detail
  536. }));
  537. }
  538. }], [{
  539. key: "var",
  540. value: function _var(name) {
  541. var element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.body;
  542. return window.getComputedStyle(element).getPropertyValue(name).trim();
  543. }
  544. }]);
  545. return PFElement;
  546. }(HTMLElement);
  547. autoReveal(PFElement.log);
  548. return PFElement;
  549. })));
  550. //# sourceMappingURL=pfelement.umd.js.map