style-map.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /**
  2. * @license
  3. * Copyright 2018 Google LLC
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. import { noChange } from '../lit-html.js';
  7. import { directive, Directive, PartType, } from '../directive.js';
  8. class StyleMapDirective extends Directive {
  9. constructor(partInfo) {
  10. var _a;
  11. super(partInfo);
  12. if (partInfo.type !== PartType.ATTRIBUTE ||
  13. partInfo.name !== 'style' ||
  14. ((_a = partInfo.strings) === null || _a === void 0 ? void 0 : _a.length) > 2) {
  15. throw new Error('The `styleMap` directive must be used in the `style` attribute ' +
  16. 'and must be the only part in the attribute.');
  17. }
  18. }
  19. render(styleInfo) {
  20. return Object.keys(styleInfo).reduce((style, prop) => {
  21. const value = styleInfo[prop];
  22. if (value == null) {
  23. return style;
  24. }
  25. // Convert property names from camel-case to dash-case, i.e.:
  26. // `backgroundColor` -> `background-color`
  27. // Vendor-prefixed names need an extra `-` appended to front:
  28. // `webkitAppearance` -> `-webkit-appearance`
  29. // Exception is any property name containing a dash, including
  30. // custom properties; we assume these are already dash-cased i.e.:
  31. // `--my-button-color` --> `--my-button-color`
  32. prop = prop
  33. .replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g, '-$&')
  34. .toLowerCase();
  35. return style + `${prop}:${value};`;
  36. }, '');
  37. }
  38. update(part, [styleInfo]) {
  39. const { style } = part.element;
  40. if (this._previousStyleProperties === undefined) {
  41. this._previousStyleProperties = new Set();
  42. for (const name in styleInfo) {
  43. this._previousStyleProperties.add(name);
  44. }
  45. return this.render(styleInfo);
  46. }
  47. // Remove old properties that no longer exist in styleInfo
  48. // We use forEach() instead of for-of so that re don't require down-level
  49. // iteration.
  50. this._previousStyleProperties.forEach((name) => {
  51. // If the name isn't in styleInfo or it's null/undefined
  52. if (styleInfo[name] == null) {
  53. this._previousStyleProperties.delete(name);
  54. if (name.includes('-')) {
  55. style.removeProperty(name);
  56. }
  57. else {
  58. // Note reset using empty string (vs null) as IE11 does not always
  59. // reset via null (https://developer.mozilla.org/en-US/docs/Web/API/ElementCSSInlineStyle/style#setting_styles)
  60. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  61. style[name] = '';
  62. }
  63. }
  64. });
  65. // Add or update properties
  66. for (const name in styleInfo) {
  67. const value = styleInfo[name];
  68. if (value != null) {
  69. this._previousStyleProperties.add(name);
  70. if (name.includes('-')) {
  71. style.setProperty(name, value);
  72. }
  73. else {
  74. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  75. style[name] = value;
  76. }
  77. }
  78. }
  79. return noChange;
  80. }
  81. }
  82. /**
  83. * A directive that applies CSS properties to an element.
  84. *
  85. * `styleMap` can only be used in the `style` attribute and must be the only
  86. * expression in the attribute. It takes the property names in the `styleInfo`
  87. * object and adds the property values as CSS properties. Property names with
  88. * dashes (`-`) are assumed to be valid CSS property names and set on the
  89. * element's style object using `setProperty()`. Names without dashes are
  90. * assumed to be camelCased JavaScript property names and set on the element's
  91. * style object using property assignment, allowing the style object to
  92. * translate JavaScript-style names to CSS property names.
  93. *
  94. * For example `styleMap({backgroundColor: 'red', 'border-top': '5px', '--size':
  95. * '0'})` sets the `background-color`, `border-top` and `--size` properties.
  96. *
  97. * @param styleInfo
  98. */
  99. export const styleMap = directive(StyleMapDirective);
  100. //# sourceMappingURL=style-map.js.map