index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. var React = require('react');
  2. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  3. var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
  4. /*
  5. Based on Glamor's sheet
  6. https://github.com/threepointone/glamor/blob/667b480d31b3721a905021b26e1290ce92ca2879/src/sheet.js
  7. */ function _defineProperties(target, props) {
  8. for(var i = 0; i < props.length; i++){
  9. var descriptor = props[i];
  10. descriptor.enumerable = descriptor.enumerable || false;
  11. descriptor.configurable = true;
  12. if ("value" in descriptor) descriptor.writable = true;
  13. Object.defineProperty(target, descriptor.key, descriptor);
  14. }
  15. }
  16. function _createClass(Constructor, protoProps, staticProps) {
  17. if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  18. if (staticProps) _defineProperties(Constructor, staticProps);
  19. return Constructor;
  20. }
  21. var isProd = typeof process !== "undefined" && process.env && process.env.NODE_ENV === "production";
  22. var isString = function(o) {
  23. return Object.prototype.toString.call(o) === "[object String]";
  24. };
  25. var StyleSheet = /*#__PURE__*/ function() {
  26. function StyleSheet(param) {
  27. var ref = param === void 0 ? {} : param, _name = ref.name, name = _name === void 0 ? "stylesheet" : _name, _optimizeForSpeed = ref.optimizeForSpeed, optimizeForSpeed = _optimizeForSpeed === void 0 ? isProd : _optimizeForSpeed;
  28. invariant$1(isString(name), "`name` must be a string");
  29. this._name = name;
  30. this._deletedRulePlaceholder = "#" + name + "-deleted-rule____{}";
  31. invariant$1(typeof optimizeForSpeed === "boolean", "`optimizeForSpeed` must be a boolean");
  32. this._optimizeForSpeed = optimizeForSpeed;
  33. this._serverSheet = undefined;
  34. this._tags = [];
  35. this._injected = false;
  36. this._rulesCount = 0;
  37. var node = typeof window !== "undefined" && document.querySelector('meta[property="csp-nonce"]');
  38. this._nonce = node ? node.getAttribute("content") : null;
  39. }
  40. var _proto = StyleSheet.prototype;
  41. _proto.setOptimizeForSpeed = function setOptimizeForSpeed(bool) {
  42. invariant$1(typeof bool === "boolean", "`setOptimizeForSpeed` accepts a boolean");
  43. invariant$1(this._rulesCount === 0, "optimizeForSpeed cannot be when rules have already been inserted");
  44. this.flush();
  45. this._optimizeForSpeed = bool;
  46. this.inject();
  47. };
  48. _proto.isOptimizeForSpeed = function isOptimizeForSpeed() {
  49. return this._optimizeForSpeed;
  50. };
  51. _proto.inject = function inject() {
  52. var _this = this;
  53. invariant$1(!this._injected, "sheet already injected");
  54. this._injected = true;
  55. if (typeof window !== "undefined" && this._optimizeForSpeed) {
  56. this._tags[0] = this.makeStyleTag(this._name);
  57. this._optimizeForSpeed = "insertRule" in this.getSheet();
  58. if (!this._optimizeForSpeed) {
  59. if (!isProd) {
  60. console.warn("StyleSheet: optimizeForSpeed mode not supported falling back to standard mode.");
  61. }
  62. this.flush();
  63. this._injected = true;
  64. }
  65. return;
  66. }
  67. this._serverSheet = {
  68. cssRules: [],
  69. insertRule: function(rule, index) {
  70. if (typeof index === "number") {
  71. _this._serverSheet.cssRules[index] = {
  72. cssText: rule
  73. };
  74. } else {
  75. _this._serverSheet.cssRules.push({
  76. cssText: rule
  77. });
  78. }
  79. return index;
  80. },
  81. deleteRule: function(index) {
  82. _this._serverSheet.cssRules[index] = null;
  83. }
  84. };
  85. };
  86. _proto.getSheetForTag = function getSheetForTag(tag) {
  87. if (tag.sheet) {
  88. return tag.sheet;
  89. }
  90. // this weirdness brought to you by firefox
  91. for(var i = 0; i < document.styleSheets.length; i++){
  92. if (document.styleSheets[i].ownerNode === tag) {
  93. return document.styleSheets[i];
  94. }
  95. }
  96. };
  97. _proto.getSheet = function getSheet() {
  98. return this.getSheetForTag(this._tags[this._tags.length - 1]);
  99. };
  100. _proto.insertRule = function insertRule(rule, index) {
  101. invariant$1(isString(rule), "`insertRule` accepts only strings");
  102. if (typeof window === "undefined") {
  103. if (typeof index !== "number") {
  104. index = this._serverSheet.cssRules.length;
  105. }
  106. this._serverSheet.insertRule(rule, index);
  107. return this._rulesCount++;
  108. }
  109. if (this._optimizeForSpeed) {
  110. var sheet = this.getSheet();
  111. if (typeof index !== "number") {
  112. index = sheet.cssRules.length;
  113. }
  114. // this weirdness for perf, and chrome's weird bug
  115. // https://stackoverflow.com/questions/20007992/chrome-suddenly-stopped-accepting-insertrule
  116. try {
  117. sheet.insertRule(rule, index);
  118. } catch (error) {
  119. if (!isProd) {
  120. console.warn("StyleSheet: illegal rule: \n\n" + rule + "\n\nSee https://stackoverflow.com/q/20007992 for more info");
  121. }
  122. return -1;
  123. }
  124. } else {
  125. var insertionPoint = this._tags[index];
  126. this._tags.push(this.makeStyleTag(this._name, rule, insertionPoint));
  127. }
  128. return this._rulesCount++;
  129. };
  130. _proto.replaceRule = function replaceRule(index, rule) {
  131. if (this._optimizeForSpeed || typeof window === "undefined") {
  132. var sheet = typeof window !== "undefined" ? this.getSheet() : this._serverSheet;
  133. if (!rule.trim()) {
  134. rule = this._deletedRulePlaceholder;
  135. }
  136. if (!sheet.cssRules[index]) {
  137. // @TBD Should we throw an error?
  138. return index;
  139. }
  140. sheet.deleteRule(index);
  141. try {
  142. sheet.insertRule(rule, index);
  143. } catch (error) {
  144. if (!isProd) {
  145. console.warn("StyleSheet: illegal rule: \n\n" + rule + "\n\nSee https://stackoverflow.com/q/20007992 for more info");
  146. }
  147. // In order to preserve the indices we insert a deleteRulePlaceholder
  148. sheet.insertRule(this._deletedRulePlaceholder, index);
  149. }
  150. } else {
  151. var tag = this._tags[index];
  152. invariant$1(tag, "old rule at index `" + index + "` not found");
  153. tag.textContent = rule;
  154. }
  155. return index;
  156. };
  157. _proto.deleteRule = function deleteRule(index) {
  158. if (typeof window === "undefined") {
  159. this._serverSheet.deleteRule(index);
  160. return;
  161. }
  162. if (this._optimizeForSpeed) {
  163. this.replaceRule(index, "");
  164. } else {
  165. var tag = this._tags[index];
  166. invariant$1(tag, "rule at index `" + index + "` not found");
  167. tag.parentNode.removeChild(tag);
  168. this._tags[index] = null;
  169. }
  170. };
  171. _proto.flush = function flush() {
  172. this._injected = false;
  173. this._rulesCount = 0;
  174. if (typeof window !== "undefined") {
  175. this._tags.forEach(function(tag) {
  176. return tag && tag.parentNode.removeChild(tag);
  177. });
  178. this._tags = [];
  179. } else {
  180. // simpler on server
  181. this._serverSheet.cssRules = [];
  182. }
  183. };
  184. _proto.cssRules = function cssRules() {
  185. var _this = this;
  186. if (typeof window === "undefined") {
  187. return this._serverSheet.cssRules;
  188. }
  189. return this._tags.reduce(function(rules, tag) {
  190. if (tag) {
  191. rules = rules.concat(Array.prototype.map.call(_this.getSheetForTag(tag).cssRules, function(rule) {
  192. return rule.cssText === _this._deletedRulePlaceholder ? null : rule;
  193. }));
  194. } else {
  195. rules.push(null);
  196. }
  197. return rules;
  198. }, []);
  199. };
  200. _proto.makeStyleTag = function makeStyleTag(name, cssString, relativeToTag) {
  201. if (cssString) {
  202. invariant$1(isString(cssString), "makeStyleTag accepts only strings as second parameter");
  203. }
  204. var tag = document.createElement("style");
  205. if (this._nonce) tag.setAttribute("nonce", this._nonce);
  206. tag.type = "text/css";
  207. tag.setAttribute("data-" + name, "");
  208. if (cssString) {
  209. tag.appendChild(document.createTextNode(cssString));
  210. }
  211. var head = document.head || document.getElementsByTagName("head")[0];
  212. if (relativeToTag) {
  213. head.insertBefore(tag, relativeToTag);
  214. } else {
  215. head.appendChild(tag);
  216. }
  217. return tag;
  218. };
  219. _createClass(StyleSheet, [
  220. {
  221. key: "length",
  222. get: function get() {
  223. return this._rulesCount;
  224. }
  225. }
  226. ]);
  227. return StyleSheet;
  228. }();
  229. function invariant$1(condition, message) {
  230. if (!condition) {
  231. throw new Error("StyleSheet: " + message + ".");
  232. }
  233. }
  234. function hash(str) {
  235. var _$hash = 5381, i = str.length;
  236. while(i){
  237. _$hash = _$hash * 33 ^ str.charCodeAt(--i);
  238. }
  239. /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
  240. * integers. Since we want the results to be always positive, convert the
  241. * signed int to an unsigned by doing an unsigned bitshift. */ return _$hash >>> 0;
  242. }
  243. var stringHash = hash;
  244. var sanitize = function(rule) {
  245. return rule.replace(/\/style/gi, "\\/style");
  246. };
  247. var cache = {};
  248. /**
  249. * computeId
  250. *
  251. * Compute and memoize a jsx id from a basedId and optionally props.
  252. */ function computeId(baseId, props) {
  253. if (!props) {
  254. return "jsx-" + baseId;
  255. }
  256. var propsToString = String(props);
  257. var key = baseId + propsToString;
  258. if (!cache[key]) {
  259. cache[key] = "jsx-" + stringHash(baseId + "-" + propsToString);
  260. }
  261. return cache[key];
  262. }
  263. /**
  264. * computeSelector
  265. *
  266. * Compute and memoize dynamic selectors.
  267. */ function computeSelector(id, css) {
  268. var selectoPlaceholderRegexp = /__jsx-style-dynamic-selector/g;
  269. // Sanitize SSR-ed CSS.
  270. // Client side code doesn't need to be sanitized since we use
  271. // document.createTextNode (dev) and the CSSOM api sheet.insertRule (prod).
  272. if (typeof window === "undefined") {
  273. css = sanitize(css);
  274. }
  275. var idcss = id + css;
  276. if (!cache[idcss]) {
  277. cache[idcss] = css.replace(selectoPlaceholderRegexp, id);
  278. }
  279. return cache[idcss];
  280. }
  281. function mapRulesToStyle(cssRules, options) {
  282. if (options === void 0) options = {};
  283. return cssRules.map(function(args) {
  284. var id = args[0];
  285. var css = args[1];
  286. return /*#__PURE__*/ React__default["default"].createElement("style", {
  287. id: "__" + id,
  288. // Avoid warnings upon render with a key
  289. key: "__" + id,
  290. nonce: options.nonce ? options.nonce : undefined,
  291. dangerouslySetInnerHTML: {
  292. __html: css
  293. }
  294. });
  295. });
  296. }
  297. var StyleSheetRegistry = /*#__PURE__*/ function() {
  298. function StyleSheetRegistry(param) {
  299. var ref = param === void 0 ? {} : param, _styleSheet = ref.styleSheet, styleSheet = _styleSheet === void 0 ? null : _styleSheet, _optimizeForSpeed = ref.optimizeForSpeed, optimizeForSpeed = _optimizeForSpeed === void 0 ? false : _optimizeForSpeed;
  300. this._sheet = styleSheet || new StyleSheet({
  301. name: "styled-jsx",
  302. optimizeForSpeed: optimizeForSpeed
  303. });
  304. this._sheet.inject();
  305. if (styleSheet && typeof optimizeForSpeed === "boolean") {
  306. this._sheet.setOptimizeForSpeed(optimizeForSpeed);
  307. this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
  308. }
  309. this._fromServer = undefined;
  310. this._indices = {};
  311. this._instancesCounts = {};
  312. }
  313. var _proto = StyleSheetRegistry.prototype;
  314. _proto.add = function add(props) {
  315. var _this = this;
  316. if (undefined === this._optimizeForSpeed) {
  317. this._optimizeForSpeed = Array.isArray(props.children);
  318. this._sheet.setOptimizeForSpeed(this._optimizeForSpeed);
  319. this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
  320. }
  321. if (typeof window !== "undefined" && !this._fromServer) {
  322. this._fromServer = this.selectFromServer();
  323. this._instancesCounts = Object.keys(this._fromServer).reduce(function(acc, tagName) {
  324. acc[tagName] = 0;
  325. return acc;
  326. }, {});
  327. }
  328. var ref = this.getIdAndRules(props), styleId = ref.styleId, rules = ref.rules;
  329. // Deduping: just increase the instances count.
  330. if (styleId in this._instancesCounts) {
  331. this._instancesCounts[styleId] += 1;
  332. return;
  333. }
  334. var indices = rules.map(function(rule) {
  335. return _this._sheet.insertRule(rule);
  336. })// Filter out invalid rules
  337. .filter(function(index) {
  338. return index !== -1;
  339. });
  340. this._indices[styleId] = indices;
  341. this._instancesCounts[styleId] = 1;
  342. };
  343. _proto.remove = function remove(props) {
  344. var _this = this;
  345. var styleId = this.getIdAndRules(props).styleId;
  346. invariant(styleId in this._instancesCounts, "styleId: `" + styleId + "` not found");
  347. this._instancesCounts[styleId] -= 1;
  348. if (this._instancesCounts[styleId] < 1) {
  349. var tagFromServer = this._fromServer && this._fromServer[styleId];
  350. if (tagFromServer) {
  351. tagFromServer.parentNode.removeChild(tagFromServer);
  352. delete this._fromServer[styleId];
  353. } else {
  354. this._indices[styleId].forEach(function(index) {
  355. return _this._sheet.deleteRule(index);
  356. });
  357. delete this._indices[styleId];
  358. }
  359. delete this._instancesCounts[styleId];
  360. }
  361. };
  362. _proto.update = function update(props, nextProps) {
  363. this.add(nextProps);
  364. this.remove(props);
  365. };
  366. _proto.flush = function flush() {
  367. this._sheet.flush();
  368. this._sheet.inject();
  369. this._fromServer = undefined;
  370. this._indices = {};
  371. this._instancesCounts = {};
  372. };
  373. _proto.cssRules = function cssRules() {
  374. var _this = this;
  375. var fromServer = this._fromServer ? Object.keys(this._fromServer).map(function(styleId) {
  376. return [
  377. styleId,
  378. _this._fromServer[styleId]
  379. ];
  380. }) : [];
  381. var cssRules1 = this._sheet.cssRules();
  382. return fromServer.concat(Object.keys(this._indices).map(function(styleId) {
  383. return [
  384. styleId,
  385. _this._indices[styleId].map(function(index) {
  386. return cssRules1[index].cssText;
  387. }).join(_this._optimizeForSpeed ? "" : "\n")
  388. ];
  389. })// filter out empty rules
  390. .filter(function(rule) {
  391. return Boolean(rule[1]);
  392. }));
  393. };
  394. _proto.styles = function styles(options) {
  395. return mapRulesToStyle(this.cssRules(), options);
  396. };
  397. _proto.getIdAndRules = function getIdAndRules(props) {
  398. var css = props.children, dynamic = props.dynamic, id = props.id;
  399. if (dynamic) {
  400. var styleId = computeId(id, dynamic);
  401. return {
  402. styleId: styleId,
  403. rules: Array.isArray(css) ? css.map(function(rule) {
  404. return computeSelector(styleId, rule);
  405. }) : [
  406. computeSelector(styleId, css)
  407. ]
  408. };
  409. }
  410. return {
  411. styleId: computeId(id),
  412. rules: Array.isArray(css) ? css : [
  413. css
  414. ]
  415. };
  416. };
  417. /**
  418. * selectFromServer
  419. *
  420. * Collects style tags from the document with id __jsx-XXX
  421. */ _proto.selectFromServer = function selectFromServer() {
  422. var elements = Array.prototype.slice.call(document.querySelectorAll('[id^="__jsx-"]'));
  423. return elements.reduce(function(acc, element) {
  424. var id = element.id.slice(2);
  425. acc[id] = element;
  426. return acc;
  427. }, {});
  428. };
  429. return StyleSheetRegistry;
  430. }();
  431. function invariant(condition, message) {
  432. if (!condition) {
  433. throw new Error("StyleSheetRegistry: " + message + ".");
  434. }
  435. }
  436. var StyleSheetContext = /*#__PURE__*/ React.createContext(null);
  437. StyleSheetContext.displayName = "StyleSheetContext";
  438. function createStyleRegistry() {
  439. return new StyleSheetRegistry();
  440. }
  441. function StyleRegistry(param) {
  442. var configuredRegistry = param.registry, children = param.children;
  443. var rootRegistry = React.useContext(StyleSheetContext);
  444. var ref = React.useState(function() {
  445. return rootRegistry || configuredRegistry || createStyleRegistry();
  446. }), registry = ref[0];
  447. return /*#__PURE__*/ React__default["default"].createElement(StyleSheetContext.Provider, {
  448. value: registry
  449. }, children);
  450. }
  451. function useStyleRegistry() {
  452. return React.useContext(StyleSheetContext);
  453. }
  454. // Opt-into the new `useInsertionEffect` API in React 18, fallback to `useLayoutEffect`.
  455. // https://github.com/reactwg/react-18/discussions/110
  456. var useInsertionEffect = React__default["default"].useInsertionEffect || React__default["default"].useLayoutEffect;
  457. var defaultRegistry = typeof window !== "undefined" ? createStyleRegistry() : undefined;
  458. function JSXStyle(props) {
  459. var registry = defaultRegistry ? defaultRegistry : useStyleRegistry();
  460. // If `registry` does not exist, we do nothing here.
  461. if (!registry) {
  462. return null;
  463. }
  464. if (typeof window === "undefined") {
  465. registry.add(props);
  466. return null;
  467. }
  468. useInsertionEffect(function() {
  469. registry.add(props);
  470. return function() {
  471. registry.remove(props);
  472. };
  473. // props.children can be string[], will be striped since id is identical
  474. }, [
  475. props.id,
  476. String(props.dynamic)
  477. ]);
  478. return null;
  479. }JSXStyle.dynamic = function(info) {
  480. return info.map(function(tagInfo) {
  481. var baseId = tagInfo[0];
  482. var props = tagInfo[1];
  483. return computeId(baseId, props);
  484. }).join(" ");
  485. };
  486. exports.StyleRegistry = StyleRegistry;
  487. exports.createStyleRegistry = createStyleRegistry;
  488. exports.style = JSXStyle;
  489. exports.useStyleRegistry = useStyleRegistry;