diff --git a/docs/manifest.json b/docs/manifest.json index 0616aeb2a8e7f8..5b560325a505f5 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1721,6 +1721,12 @@ "markdown_source": "../packages/global-styles-engine/README.md", "parent": "packages" }, + { + "title": "@wordpress/global-styles-ui", + "slug": "packages-global-styles-ui", + "markdown_source": "../packages/global-styles-ui/README.md", + "parent": "packages" + }, { "title": "@wordpress/hooks", "slug": "packages-hooks", diff --git a/docs/private-apis.md b/docs/private-apis.md index 31699f64da7f83..418c50d18c27f0 100644 --- a/docs/private-apis.md +++ b/docs/private-apis.md @@ -277,8 +277,6 @@ Private exports: - `EntitiesSavedStatesExtensible` - `Editor` - `EditorContentSlotFill` -- `GlobalStylesProvider` -- `mergeBaseAndUserConfigs` - `PluginPostExcerpt` - `PostCardPanel` - `PreferencesModal` diff --git a/package-lock.json b/package-lock.json index 026d4cdf1d6d8c..cc746d2debb6a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16847,6 +16847,10 @@ "resolved": "packages/global-styles-engine", "link": true }, + "node_modules/@wordpress/global-styles-ui": { + "resolved": "packages/global-styles-ui", + "link": true + }, "node_modules/@wordpress/hooks": { "resolved": "packages/hooks", "link": true @@ -20479,6 +20483,12 @@ "node": ">=0.10.0" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -52332,6 +52342,7 @@ "@wordpress/escape-html": "file:../escape-html", "@wordpress/fields": "file:../fields", "@wordpress/global-styles-engine": "file:../global-styles-engine", + "@wordpress/global-styles-ui": "file:../global-styles-ui", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", @@ -52435,6 +52446,7 @@ "@wordpress/dom": "file:../dom", "@wordpress/element": "file:../element", "@wordpress/fields": "file:../fields", + "@wordpress/global-styles-engine": "file:../global-styles-engine", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", @@ -52458,9 +52470,7 @@ "client-zip": "^2.4.5", "clsx": "^2.1.1", "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", "fast-deep-equal": "^3.1.3", - "is-plain-object": "^5.0.0", "memize": "^2.1.0", "react-autosize-textarea": "^7.1.0", "remove-accents": "^0.5.0", @@ -52685,6 +52695,41 @@ "npm": ">=8.19.2" } }, + "packages/global-styles-ui": { + "name": "@wordpress/global-styles-ui", + "version": "1.0.0", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/a11y": "file:../a11y", + "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/block-editor": "file:../block-editor", + "@wordpress/blocks": "file:../blocks", + "@wordpress/components": "file:../components", + "@wordpress/compose": "file:../compose", + "@wordpress/core-data": "file:../core-data", + "@wordpress/data": "file:../data", + "@wordpress/date": "file:../date", + "@wordpress/element": "file:../element", + "@wordpress/global-styles-engine": "file:../global-styles-engine", + "@wordpress/i18n": "file:../i18n", + "@wordpress/icons": "file:../icons", + "@wordpress/keycodes": "file:../keycodes", + "@wordpress/private-apis": "file:../private-apis", + "change-case": "^4.1.2", + "classnames": "^2.3.2", + "clsx": "^2.1.0", + "colord": "^2.7.0", + "fast-deep-equal": "^3.1.3" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "packages/hooks": { "name": "@wordpress/hooks", "version": "4.33.0", diff --git a/packages/block-editor/src/components/global-styles/README.md b/packages/block-editor/src/components/global-styles/README.md deleted file mode 100644 index 2ddb23cd01f704..00000000000000 --- a/packages/block-editor/src/components/global-styles/README.md +++ /dev/null @@ -1,190 +0,0 @@ -# Global Styles - -This folder contains all the necessary APIs to manipulate the global styles data. It can be potentially extracted to its own package. - -# Available public APIs - -## useGlobalStylesReset - -A React hook used to retrieve whether the Global Styles have been edited and a callback to reset to the default theme values. - -```js -import { useGlobalStylesReset } from '@wordpress/block-editor'; - -function MyComponent() { - const [ canReset, reset ] = useGlobalStylesReset(); - - return canReset ? : null; -} -``` - -## useGlobalStylesOutput - -A React hook used to retrieve the styles array and settings to provide for block editor instances based on the current global styles. - -```js -import { - useGlobalStylesOutput, - BlockEditorProvider, - BlockList, -} from '@wordpress/block-editor'; - -function MyComponent() { - const [ styles, settings ] = useGlobalStylesOutput(); - - return ( - - - - ); -} -``` - -## useGlobalStyle - -A react hook used to retrieve the style applied to a given context. - -```js -import { useGlobalStyle } from '@wordpress/block-editor'; - -function MyComponent() { - // Text color for the site root. - const [ color, setColor ] = useGlobalStyle( 'color.text' ); - - // The user modified color for the core paragraph block. - const [ pColor, setPColor ] = useGlobalStyle( - 'color.text', - 'core/paragraph', - 'user' - ); - - return 'Something'; -} -``` - -## useGlobalSetting - -A react hook used to retrieve the setting applied to a given context. - -```js -import { useGlobalSetting } from '@wordpress/block-editor'; - -function MyComponent() { - // The theme color palette. - const [ colorPalette, setColorPalette ] = useGlobalSetting( - 'color.palette.theme' - ); - - // The theme color palette for the paragraph block, ignoring user changes. - // If the palette is not defined for the paragraph block, the root one is returned. - const [ pColor, setPColor ] = useGlobalSetting( - 'color.palette.theme', - 'core/paragraph', - 'base' - ); - - return 'Something'; -} -``` - -## UI Components - -The global styles folder also offers a set of reusable UI components. These components follow a strict set of guidelines: - -- They are independent of any context or any store dependency. They only rely on the props passed to them. -- They receive a similar set of props: - - - `value`: The value is a style object that maps closely the format used in `theme.json` and is also very close to the format of the `style` attributes for blocks. There are some differences with the block attributes due to the iteration process and the fact that we need to maintain compatibility with the existing blocks even if they predate the introduction of Global Styles and these UI components. An example value for a style object is: - -```js -{ - color: { - text: 'var:preset|color|blue', - background: '#FF0000', - }, - typography: { - fontFamily: 'var:preset|font-family|base', - fontSize: '10px', - lineHeight: 1.5, - }, - spacing: { - padding: 'var:preset|spacing|medium', - }, - elements: { - link: { - color: { - text: 'var:preset|color|green', - }, - }, - }, -} -``` - -- `onChange`: A callback that receives the new value and is called when the user changes the value of the UI component. -- `inheritedValue`: The inherited value is a style object that represents the combined value of the style inherited from the parent context in addition to the style applied to the current context. The format is the same as the `value` prop. -- `settings`: The settings are the theme.json settings. They are used to provide the UI components with the necessary information to render the UI. An example value for the settings is: - -```js -{ - color: { - palette: { - custom: [ - { - slug: 'black', - color: '#000000', - }, - { - slug: 'white', - color: '#FFFFFF', - }, - { - slug: 'blue', - color: '#0000FF', - }, - ] - }, - gradients: { - custom: [ - { - slug: 'gradient-1', - gradient: 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', - }, - { - slug: 'gradient-2', - gradient: 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', - }, - ] - }, - }, - typography: { - fontSizes: [ - { - slug: 'small', - size: '12px', - }, - { - slug: 'medium', - size: '16px', - }, - { - slug: 'large', - size: '24px', - }, - ], - } -} -``` -- `defaultControls`: The default controls are the controls that are used by default to render the UI. They are used to provide the UI components with the necessary information to render the UI. An example value for the default controls for the `ColorPanel` component is: - -```js -{ - background: true, - text: true, - link: true, -}, -``` diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index c36a1ecc0bfaf2..ebf683f207727f 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -1,136 +1,16 @@ -/** - * External dependencies - */ -import fastDeepEqual from 'fast-deep-equal/es6'; - /** * WordPress dependencies */ -import { useContext, useCallback, useMemo } from '@wordpress/element'; +import { useMemo } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { store as blocksStore } from '@wordpress/blocks'; import { _x } from '@wordpress/i18n'; -import { - getSetting, - getStyle, - getPresetVariableFromValue, -} from '@wordpress/global-styles-engine'; /** * Internal dependencies */ -import { setImmutably } from '../../utils/object'; -import { GlobalStylesContext } from './context'; import { unlock } from '../../lock-unlock'; -const EMPTY_CONFIG = { settings: {}, styles: {} }; - -export const useGlobalStylesReset = () => { - const { user, setUserConfig } = useContext( GlobalStylesContext ); - const config = { - settings: user.settings, - styles: user.styles, - }; - const canReset = !! config && ! fastDeepEqual( config, EMPTY_CONFIG ); - return [ - canReset, - useCallback( () => setUserConfig( EMPTY_CONFIG ), [ setUserConfig ] ), - ]; -}; - -export function useGlobalSetting( propertyPath, blockName, source = 'all' ) { - const { setUserConfig, ...configs } = useContext( GlobalStylesContext ); - const appendedBlockPath = blockName ? '.blocks.' + blockName : ''; - const appendedPropertyPath = propertyPath ? '.' + propertyPath : ''; - const contextualPath = `settings${ appendedBlockPath }${ appendedPropertyPath }`; - const sourceKey = source === 'all' ? 'merged' : source; - - const settingValue = useMemo( () => { - const configToUse = configs[ sourceKey ]; - if ( ! configToUse ) { - throw 'Unsupported source'; - } - - // Use engine's getSetting instead of duplicating logic - return getSetting( configToUse, propertyPath, blockName ); - }, [ configs, sourceKey, propertyPath, blockName ] ); - - const setSetting = ( newValue ) => { - setUserConfig( ( currentConfig ) => - setImmutably( currentConfig, contextualPath.split( '.' ), newValue ) - ); - }; - return [ settingValue, setSetting ]; -} - -export function useGlobalStyle( - path, - blockName, - source = 'all', - { shouldDecodeEncode = true } = {} -) { - const { - merged: mergedConfig, - base: baseConfig, - user: userConfig, - setUserConfig, - } = useContext( GlobalStylesContext ); - const appendedPath = path ? '.' + path : ''; - const finalPath = ! blockName - ? `styles${ appendedPath }` - : `styles.blocks.${ blockName }${ appendedPath }`; - - const setStyle = ( newValue ) => { - setUserConfig( ( currentConfig ) => - setImmutably( - currentConfig, - finalPath.split( '.' ), - shouldDecodeEncode - ? getPresetVariableFromValue( - mergedConfig.settings, - blockName, - path, - newValue - ) - : newValue - ) - ); - }; - - let result; - // Use engine's getStyle instead of duplicating logic - switch ( source ) { - case 'all': - result = getStyle( - mergedConfig, - path, - blockName, - shouldDecodeEncode - ); - break; - case 'user': - result = getStyle( - userConfig, - path, - blockName, - shouldDecodeEncode - ); - break; - case 'base': - result = getStyle( - baseConfig, - path, - blockName, - shouldDecodeEncode - ); - break; - default: - throw 'Unsupported source'; - } - - return [ result, setStyle ]; -} - /** * React hook that overrides a global settings object with block and element specific settings. * diff --git a/packages/block-editor/src/components/global-styles/index.js b/packages/block-editor/src/components/global-styles/index.js index eaa1ba29805dad..4bed61d2cf535a 100644 --- a/packages/block-editor/src/components/global-styles/index.js +++ b/packages/block-editor/src/components/global-styles/index.js @@ -1,9 +1,4 @@ -export { - useGlobalStylesReset, - useGlobalSetting, - useGlobalStyle, - useSettingsForBlockElement, -} from './hooks'; +export { useSettingsForBlockElement } from './hooks'; export { GlobalStylesContext } from './context'; export { default as TypographyPanel, diff --git a/packages/block-library/src/accordion-item/block.json b/packages/block-library/src/accordion-item/block.json index a505ec97f109b9..1ae1b60bc34544 100644 --- a/packages/block-library/src/accordion-item/block.json +++ b/packages/block-library/src/accordion-item/block.json @@ -33,7 +33,7 @@ "shadow": true, "layout": { "allowEditing": false - }, + }, "typography": { "fontSize": true, "lineHeight": true, diff --git a/packages/edit-site/lib/inflate.js b/packages/edit-site/lib/inflate.js deleted file mode 100644 index 596d1cb5b8013c..00000000000000 --- a/packages/edit-site/lib/inflate.js +++ /dev/null @@ -1,3333 +0,0 @@ -/** - * Credits: - * - * lib-font - * https://github.com/Pomax/lib-font - * https://github.com/Pomax/lib-font/blob/master/lib/inflate.js - * - * The MIT License (MIT) - * - * Copyright (c) 2020 pomax@nihongoresources.com - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint eslint-comments/no-unlimited-disable: 0 */ -/* eslint-disable */ -/* pako 1.0.10 nodeca/pako */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pako = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1); - } - _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start - - - // convert string to array (typed, when possible) - exports.string2buf = function (str) { - var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; - - // count binary size - for (m_pos = 0; m_pos < str_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { - c2 = str.charCodeAt(m_pos + 1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; - } - - // allocate buffer - buf = new utils.Buf8(buf_len); - - // convert - for (i = 0, m_pos = 0; i < buf_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { - c2 = str.charCodeAt(m_pos + 1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - if (c < 0x80) { - /* one byte */ - buf[i++] = c; - } else if (c < 0x800) { - /* two bytes */ - buf[i++] = 0xC0 | (c >>> 6); - buf[i++] = 0x80 | (c & 0x3f); - } else if (c < 0x10000) { - /* three bytes */ - buf[i++] = 0xE0 | (c >>> 12); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } else { - /* four bytes */ - buf[i++] = 0xf0 | (c >>> 18); - buf[i++] = 0x80 | (c >>> 12 & 0x3f); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } - } - - return buf; - }; - - // Helper (used in 2 places) - function buf2binstring(buf, len) { - // On Chrome, the arguments in a function call that are allowed is `65534`. - // If the length of the buffer is smaller than that, we can use this optimization, - // otherwise we will take a slower path. - if (len < 65534) { - if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) { - return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len)); - } - } - - var result = ''; - for (var i = 0; i < len; i++) { - result += String.fromCharCode(buf[i]); - } - return result; - } - - - // Convert byte array to binary string - exports.buf2binstring = function (buf) { - return buf2binstring(buf, buf.length); - }; - - - // Convert binary string (typed, when possible) - exports.binstring2buf = function (str) { - var buf = new utils.Buf8(str.length); - for (var i = 0, len = buf.length; i < len; i++) { - buf[i] = str.charCodeAt(i); - } - return buf; - }; - - - // convert array to string - exports.buf2string = function (buf, max) { - var i, out, c, c_len; - var len = max || buf.length; - - // Reserve max possible length (2 words per char) - // NB: by unknown reasons, Array is significantly faster for - // String.fromCharCode.apply than Uint16Array. - var utf16buf = new Array(len * 2); - - for (out = 0, i = 0; i < len;) { - c = buf[i++]; - // quick process ascii - if (c < 0x80) { utf16buf[out++] = c; continue; } - - c_len = _utf8len[c]; - // skip 5 & 6 byte codes - if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; } - - // apply mask on first byte - c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; - // join the rest - while (c_len > 1 && i < len) { - c = (c << 6) | (buf[i++] & 0x3f); - c_len--; - } - - // terminated by end of string? - if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } - - if (c < 0x10000) { - utf16buf[out++] = c; - } else { - c -= 0x10000; - utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); - utf16buf[out++] = 0xdc00 | (c & 0x3ff); - } - } - - return buf2binstring(utf16buf, out); - }; - - - // Calculate max possible position in utf8 buffer, - // that will not break sequence. If that's not possible - // - (very small limits) return max size as is. - // - // buf[] - utf8 bytes array - // max - length limit (mandatory); - exports.utf8border = function (buf, max) { - var pos; - - max = max || buf.length; - if (max > buf.length) { max = buf.length; } - - // go back from last position, until start of sequence found - pos = max - 1; - while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } - - // Very small and broken sequence, - // return max, because we should return something anyway. - if (pos < 0) { return max; } - - // If we came to start of buffer - that means buffer is too small, - // return max too. - if (pos === 0) { return max; } - - return (pos + _utf8len[buf[pos]] > max) ? pos : max; - }; - - },{"./common":1}],3:[function(require,module,exports){ - 'use strict'; - - // Note: adler32 takes 12% for level 0 and 2% for level 6. - // It isn't worth it to make additional optimizations as in original. - // Small size is preferable. - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - function adler32(adler, buf, len, pos) { - var s1 = (adler & 0xffff) |0, - s2 = ((adler >>> 16) & 0xffff) |0, - n = 0; - - while (len !== 0) { - // Set limit ~ twice less than 5552, to keep - // s2 in 31-bits, because we force signed ints. - // in other case %= will fail. - n = len > 2000 ? 2000 : len; - len -= n; - - do { - s1 = (s1 + buf[pos++]) |0; - s2 = (s2 + s1) |0; - } while (--n); - - s1 %= 65521; - s2 %= 65521; - } - - return (s1 | (s2 << 16)) |0; - } - - - module.exports = adler32; - - },{}],4:[function(require,module,exports){ - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - module.exports = { - - /* Allowed flush values; see deflate() and inflate() below for details */ - Z_NO_FLUSH: 0, - Z_PARTIAL_FLUSH: 1, - Z_SYNC_FLUSH: 2, - Z_FULL_FLUSH: 3, - Z_FINISH: 4, - Z_BLOCK: 5, - Z_TREES: 6, - - /* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - Z_OK: 0, - Z_STREAM_END: 1, - Z_NEED_DICT: 2, - Z_ERRNO: -1, - Z_STREAM_ERROR: -2, - Z_DATA_ERROR: -3, - //Z_MEM_ERROR: -4, - Z_BUF_ERROR: -5, - //Z_VERSION_ERROR: -6, - - /* compression levels */ - Z_NO_COMPRESSION: 0, - Z_BEST_SPEED: 1, - Z_BEST_COMPRESSION: 9, - Z_DEFAULT_COMPRESSION: -1, - - - Z_FILTERED: 1, - Z_HUFFMAN_ONLY: 2, - Z_RLE: 3, - Z_FIXED: 4, - Z_DEFAULT_STRATEGY: 0, - - /* Possible values of the data_type field (though see inflate()) */ - Z_BINARY: 0, - Z_TEXT: 1, - //Z_ASCII: 1, // = Z_TEXT (deprecated) - Z_UNKNOWN: 2, - - /* The deflate compression method */ - Z_DEFLATED: 8 - //Z_NULL: null // Use -1 or null inline, depending on var type - }; - - },{}],5:[function(require,module,exports){ - 'use strict'; - - // Note: we can't get significant speed boost here. - // So write code to minimize size - no pregenerated tables - // and array tools dependencies. - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - // Use ordinary array, since untyped makes no boost here - function makeTable() { - var c, table = []; - - for (var n = 0; n < 256; n++) { - c = n; - for (var k = 0; k < 8; k++) { - c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); - } - table[n] = c; - } - - return table; - } - - // Create table on load. Just 255 signed longs. Not a problem. - var crcTable = makeTable(); - - - function crc32(crc, buf, len, pos) { - var t = crcTable, - end = pos + len; - - crc ^= -1; - - for (var i = pos; i < end; i++) { - crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; - } - - return (crc ^ (-1)); // >>> 0; - } - - - module.exports = crc32; - - },{}],6:[function(require,module,exports){ - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - function GZheader() { - /* true if compressed data believed to be text */ - this.text = 0; - /* modification time */ - this.time = 0; - /* extra flags (not used when writing a gzip file) */ - this.xflags = 0; - /* operating system */ - this.os = 0; - /* pointer to extra field or Z_NULL if none */ - this.extra = null; - /* extra field length (valid if extra != Z_NULL) */ - this.extra_len = 0; // Actually, we don't need it in JS, - // but leave for few code modifications - - // - // Setup limits is not necessary because in js we should not preallocate memory - // for inflate use constant limit in 65536 bytes - // - - /* space at extra (only when reading header) */ - // this.extra_max = 0; - /* pointer to zero-terminated file name or Z_NULL */ - this.name = ''; - /* space at name (only when reading header) */ - // this.name_max = 0; - /* pointer to zero-terminated comment or Z_NULL */ - this.comment = ''; - /* space at comment (only when reading header) */ - // this.comm_max = 0; - /* true if there was or will be a header crc */ - this.hcrc = 0; - /* true when done reading gzip header (not used when writing a gzip file) */ - this.done = false; - } - - module.exports = GZheader; - - },{}],7:[function(require,module,exports){ - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - // See state defs from inflate.js - var BAD = 30; /* got a data error -- remain here until reset */ - var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ - - /* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state.mode === LEN - strm.avail_in >= 6 - strm.avail_out >= 258 - start >= strm.avail_out - state.bits < 8 - - On return, state.mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm.avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm.avail_out >= 258 for each loop to avoid checking for - output space. - */ - module.exports = function inflate_fast(strm, start) { - var state; - var _in; /* local strm.input */ - var last; /* have enough input while in < last */ - var _out; /* local strm.output */ - var beg; /* inflate()'s initial strm.output */ - var end; /* while out < end, enough space available */ - //#ifdef INFLATE_STRICT - var dmax; /* maximum distance from zlib header */ - //#endif - var wsize; /* window size or zero if not using window */ - var whave; /* valid bytes in the window */ - var wnext; /* window write index */ - // Use `s_window` instead `window`, avoid conflict with instrumentation tools - var s_window; /* allocated sliding window, if wsize != 0 */ - var hold; /* local strm.hold */ - var bits; /* local strm.bits */ - var lcode; /* local strm.lencode */ - var dcode; /* local strm.distcode */ - var lmask; /* mask for first level of length codes */ - var dmask; /* mask for first level of distance codes */ - var here; /* retrieved table entry */ - var op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - var len; /* match length, unused bytes */ - var dist; /* match distance */ - var from; /* where to copy match from */ - var from_source; - - - var input, output; // JS specific, because we have no pointers - - /* copy state to local variables */ - state = strm.state; - //here = state.here; - _in = strm.next_in; - input = strm.input; - last = _in + (strm.avail_in - 5); - _out = strm.next_out; - output = strm.output; - beg = _out - (start - strm.avail_out); - end = _out + (strm.avail_out - 257); - //#ifdef INFLATE_STRICT - dmax = state.dmax; - //#endif - wsize = state.wsize; - whave = state.whave; - wnext = state.wnext; - s_window = state.window; - hold = state.hold; - bits = state.bits; - lcode = state.lencode; - dcode = state.distcode; - lmask = (1 << state.lenbits) - 1; - dmask = (1 << state.distbits) - 1; - - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - - top: - do { - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - - here = lcode[hold & lmask]; - - dolen: - for (;;) { // Goto emulation - op = here >>> 24/*here.bits*/; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 0xff/*here.op*/; - if (op === 0) { /* literal */ - //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - // "inflate: literal '%c'\n" : - // "inflate: literal 0x%02x\n", here.val)); - output[_out++] = here & 0xffff/*here.val*/; - } - else if (op & 16) { /* length base */ - len = here & 0xffff/*here.val*/; - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - len += hold & ((1 << op) - 1); - hold >>>= op; - bits -= op; - } - //Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - here = dcode[hold & dmask]; - - dodist: - for (;;) { // goto emulation - op = here >>> 24/*here.bits*/; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 0xff/*here.op*/; - - if (op & 16) { /* distance base */ - dist = here & 0xffff/*here.val*/; - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - } - dist += hold & ((1 << op) - 1); - //#ifdef INFLATE_STRICT - if (dist > dmax) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break top; - } - //#endif - hold >>>= op; - bits -= op; - //Tracevv((stderr, "inflate: distance %u\n", dist)); - op = _out - beg; /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - if (state.sane) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break top; - } - - // (!) This block is disabled in zlib defaults, - // don't enable it for binary compatibility - //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - // if (len <= op - whave) { - // do { - // output[_out++] = 0; - // } while (--len); - // continue top; - // } - // len -= op - whave; - // do { - // output[_out++] = 0; - // } while (--op > whave); - // if (op === 0) { - // from = _out - dist; - // do { - // output[_out++] = output[from++]; - // } while (--len); - // continue top; - // } - //#endif - } - from = 0; // window index - from_source = s_window; - if (wnext === 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - else if (wnext < op) { /* wrap around window */ - from += wsize + wnext - op; - op -= wnext; - if (op < len) { /* some from end of window */ - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = 0; - if (wnext < len) { /* some from start of window */ - op = wnext; - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - } - else { /* contiguous in window */ - from += wnext - op; - if (op < len) { /* some from window */ - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - while (len > 2) { - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - len -= 3; - } - if (len) { - output[_out++] = from_source[from++]; - if (len > 1) { - output[_out++] = from_source[from++]; - } - } - } - else { - from = _out - dist; /* copy direct from output */ - do { /* minimum length is three */ - output[_out++] = output[from++]; - output[_out++] = output[from++]; - output[_out++] = output[from++]; - len -= 3; - } while (len > 2); - if (len) { - output[_out++] = output[from++]; - if (len > 1) { - output[_out++] = output[from++]; - } - } - } - } - else if ((op & 64) === 0) { /* 2nd level distance code */ - here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; - continue dodist; - } - else { - strm.msg = 'invalid distance code'; - state.mode = BAD; - break top; - } - - break; // need to emulate goto via "continue" - } - } - else if ((op & 64) === 0) { /* 2nd level length code */ - here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; - continue dolen; - } - else if (op & 32) { /* end-of-block */ - //Tracevv((stderr, "inflate: end of block\n")); - state.mode = TYPE; - break top; - } - else { - strm.msg = 'invalid literal/length code'; - state.mode = BAD; - break top; - } - - break; // need to emulate goto via "continue" - } - } while (_in < last && _out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - _in -= len; - bits -= len << 3; - hold &= (1 << bits) - 1; - - /* update state and return */ - strm.next_in = _in; - strm.next_out = _out; - strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); - strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); - state.hold = hold; - state.bits = bits; - return; - }; - - },{}],8:[function(require,module,exports){ - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - var utils = require('../utils/common'); - var adler32 = require('./adler32'); - var crc32 = require('./crc32'); - var inflate_fast = require('./inffast'); - var inflate_table = require('./inftrees'); - - var CODES = 0; - var LENS = 1; - var DISTS = 2; - - /* Public constants ==========================================================*/ - /* ===========================================================================*/ - - - /* Allowed flush values; see deflate() and inflate() below for details */ - //var Z_NO_FLUSH = 0; - //var Z_PARTIAL_FLUSH = 1; - //var Z_SYNC_FLUSH = 2; - //var Z_FULL_FLUSH = 3; - var Z_FINISH = 4; - var Z_BLOCK = 5; - var Z_TREES = 6; - - - /* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - var Z_OK = 0; - var Z_STREAM_END = 1; - var Z_NEED_DICT = 2; - //var Z_ERRNO = -1; - var Z_STREAM_ERROR = -2; - var Z_DATA_ERROR = -3; - var Z_MEM_ERROR = -4; - var Z_BUF_ERROR = -5; - //var Z_VERSION_ERROR = -6; - - /* The deflate compression method */ - var Z_DEFLATED = 8; - - - /* STATES ====================================================================*/ - /* ===========================================================================*/ - - - var HEAD = 1; /* i: waiting for magic header */ - var FLAGS = 2; /* i: waiting for method and flags (gzip) */ - var TIME = 3; /* i: waiting for modification time (gzip) */ - var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ - var EXLEN = 5; /* i: waiting for extra length (gzip) */ - var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ - var NAME = 7; /* i: waiting for end of file name (gzip) */ - var COMMENT = 8; /* i: waiting for end of comment (gzip) */ - var HCRC = 9; /* i: waiting for header crc (gzip) */ - var DICTID = 10; /* i: waiting for dictionary check value */ - var DICT = 11; /* waiting for inflateSetDictionary() call */ - var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ - var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ - var STORED = 14; /* i: waiting for stored size (length and complement) */ - var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ - var COPY = 16; /* i/o: waiting for input or output to copy stored block */ - var TABLE = 17; /* i: waiting for dynamic block table lengths */ - var LENLENS = 18; /* i: waiting for code length code lengths */ - var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ - var LEN_ = 20; /* i: same as LEN below, but only first time in */ - var LEN = 21; /* i: waiting for length/lit/eob code */ - var LENEXT = 22; /* i: waiting for length extra bits */ - var DIST = 23; /* i: waiting for distance code */ - var DISTEXT = 24; /* i: waiting for distance extra bits */ - var MATCH = 25; /* o: waiting for output space to copy string */ - var LIT = 26; /* o: waiting for output space to write literal */ - var CHECK = 27; /* i: waiting for 32-bit check value */ - var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ - var DONE = 29; /* finished check, done -- remain here until reset */ - var BAD = 30; /* got a data error -- remain here until reset */ - var MEM = 31; /* got an inflate() memory error -- remain here until reset */ - var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ - - /* ===========================================================================*/ - - - - var ENOUGH_LENS = 852; - var ENOUGH_DISTS = 592; - //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); - - var MAX_WBITS = 15; - /* 32K LZ77 window */ - var DEF_WBITS = MAX_WBITS; - - - function zswap32(q) { - return (((q >>> 24) & 0xff) + - ((q >>> 8) & 0xff00) + - ((q & 0xff00) << 8) + - ((q & 0xff) << 24)); - } - - - function InflateState() { - this.mode = 0; /* current inflate mode */ - this.last = false; /* true if processing last block */ - this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ - this.havedict = false; /* true if dictionary provided */ - this.flags = 0; /* gzip header method and flags (0 if zlib) */ - this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ - this.check = 0; /* protected copy of check value */ - this.total = 0; /* protected copy of output count */ - // TODO: may be {} - this.head = null; /* where to save gzip header information */ - - /* sliding window */ - this.wbits = 0; /* log base 2 of requested window size */ - this.wsize = 0; /* window size or zero if not using window */ - this.whave = 0; /* valid bytes in the window */ - this.wnext = 0; /* window write index */ - this.window = null; /* allocated sliding window, if needed */ - - /* bit accumulator */ - this.hold = 0; /* input bit accumulator */ - this.bits = 0; /* number of bits in "in" */ - - /* for string and stored block copying */ - this.length = 0; /* literal or length of data to copy */ - this.offset = 0; /* distance back to copy string from */ - - /* for table and code decoding */ - this.extra = 0; /* extra bits needed */ - - /* fixed and dynamic code tables */ - this.lencode = null; /* starting table for length/literal codes */ - this.distcode = null; /* starting table for distance codes */ - this.lenbits = 0; /* index bits for lencode */ - this.distbits = 0; /* index bits for distcode */ - - /* dynamic table building */ - this.ncode = 0; /* number of code length code lengths */ - this.nlen = 0; /* number of length code lengths */ - this.ndist = 0; /* number of distance code lengths */ - this.have = 0; /* number of code lengths in lens[] */ - this.next = null; /* next available space in codes[] */ - - this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ - this.work = new utils.Buf16(288); /* work area for code table building */ - - /* - because we don't have pointers in js, we use lencode and distcode directly - as buffers so we don't need codes - */ - //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ - this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ - this.distdyn = null; /* dynamic table for distance codes (JS specific) */ - this.sane = 0; /* if false, allow invalid distance too far */ - this.back = 0; /* bits back of last unprocessed length/lit */ - this.was = 0; /* initial length of match */ - } - - function inflateResetKeep(strm) { - var state; - - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - strm.total_in = strm.total_out = state.total = 0; - strm.msg = ''; /*Z_NULL*/ - if (state.wrap) { /* to support ill-conceived Java test suite */ - strm.adler = state.wrap & 1; - } - state.mode = HEAD; - state.last = 0; - state.havedict = 0; - state.dmax = 32768; - state.head = null/*Z_NULL*/; - state.hold = 0; - state.bits = 0; - //state.lencode = state.distcode = state.next = state.codes; - state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); - state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); - - state.sane = 1; - state.back = -1; - //Tracev((stderr, "inflate: reset\n")); - return Z_OK; - } - - function inflateReset(strm) { - var state; - - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - state.wsize = 0; - state.whave = 0; - state.wnext = 0; - return inflateResetKeep(strm); - - } - - function inflateReset2(strm, windowBits) { - var wrap; - var state; - - /* get the state */ - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - - /* extract wrap request from windowBits parameter */ - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } - else { - wrap = (windowBits >> 4) + 1; - if (windowBits < 48) { - windowBits &= 15; - } - } - - /* set number of window bits, free window if different */ - if (windowBits && (windowBits < 8 || windowBits > 15)) { - return Z_STREAM_ERROR; - } - if (state.window !== null && state.wbits !== windowBits) { - state.window = null; - } - - /* update state and reset the rest of it */ - state.wrap = wrap; - state.wbits = windowBits; - return inflateReset(strm); - } - - function inflateInit2(strm, windowBits) { - var ret; - var state; - - if (!strm) { return Z_STREAM_ERROR; } - //strm.msg = Z_NULL; /* in case we return an error */ - - state = new InflateState(); - - //if (state === Z_NULL) return Z_MEM_ERROR; - //Tracev((stderr, "inflate: allocated\n")); - strm.state = state; - state.window = null/*Z_NULL*/; - ret = inflateReset2(strm, windowBits); - if (ret !== Z_OK) { - strm.state = null/*Z_NULL*/; - } - return ret; - } - - function inflateInit(strm) { - return inflateInit2(strm, DEF_WBITS); - } - - - /* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ - var virgin = true; - - var lenfix, distfix; // We have no pointers in JS, so keep tables separate - - function fixedtables(state) { - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - var sym; - - lenfix = new utils.Buf32(512); - distfix = new utils.Buf32(32); - - /* literal/length table */ - sym = 0; - while (sym < 144) { state.lens[sym++] = 8; } - while (sym < 256) { state.lens[sym++] = 9; } - while (sym < 280) { state.lens[sym++] = 7; } - while (sym < 288) { state.lens[sym++] = 8; } - - inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 }); - - /* distance table */ - sym = 0; - while (sym < 32) { state.lens[sym++] = 5; } - - inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 }); - - /* do this just once */ - virgin = false; - } - - state.lencode = lenfix; - state.lenbits = 9; - state.distcode = distfix; - state.distbits = 5; - } - - - /* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ - function updatewindow(strm, src, end, copy) { - var dist; - var state = strm.state; - - /* if it hasn't been done already, allocate space for the window */ - if (state.window === null) { - state.wsize = 1 << state.wbits; - state.wnext = 0; - state.whave = 0; - - state.window = new utils.Buf8(state.wsize); - } - - /* copy state->wsize or less output bytes into the circular window */ - if (copy >= state.wsize) { - utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0); - state.wnext = 0; - state.whave = state.wsize; - } - else { - dist = state.wsize - state.wnext; - if (dist > copy) { - dist = copy; - } - //zmemcpy(state->window + state->wnext, end - copy, dist); - utils.arraySet(state.window, src, end - copy, dist, state.wnext); - copy -= dist; - if (copy) { - //zmemcpy(state->window, end - copy, copy); - utils.arraySet(state.window, src, end - copy, copy, 0); - state.wnext = copy; - state.whave = state.wsize; - } - else { - state.wnext += dist; - if (state.wnext === state.wsize) { state.wnext = 0; } - if (state.whave < state.wsize) { state.whave += dist; } - } - } - return 0; - } - - function inflate(strm, flush) { - var state; - var input, output; // input/output buffers - var next; /* next input INDEX */ - var put; /* next output INDEX */ - var have, left; /* available input and output */ - var hold; /* bit buffer */ - var bits; /* bits in bit buffer */ - var _in, _out; /* save starting available input and output */ - var copy; /* number of stored or match bytes to copy */ - var from; /* where to copy match bytes from */ - var from_source; - var here = 0; /* current decoding table entry */ - var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) - //var last; /* parent table entry */ - var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) - var len; /* length to copy for repeats, bits to drop */ - var ret; /* return code */ - var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ - var opts; - - var n; // temporary var for NEED_BITS - - var order = /* permutation of code lengths */ - [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; - - - if (!strm || !strm.state || !strm.output || - (!strm.input && strm.avail_in !== 0)) { - return Z_STREAM_ERROR; - } - - state = strm.state; - if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ - - - //--- LOAD() --- - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - //--- - - _in = have; - _out = left; - ret = Z_OK; - - inf_leave: // goto emulation - for (;;) { - switch (state.mode) { - case HEAD: - if (state.wrap === 0) { - state.mode = TYPEDO; - break; - } - //=== NEEDBITS(16); - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ - state.check = 0/*crc32(0L, Z_NULL, 0)*/; - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = FLAGS; - break; - } - state.flags = 0; /* expect zlib header */ - if (state.head) { - state.head.done = false; - } - if (!(state.wrap & 1) || /* check if zlib header allowed */ - (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { - strm.msg = 'incorrect header check'; - state.mode = BAD; - break; - } - if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { - strm.msg = 'unknown compression method'; - state.mode = BAD; - break; - } - //--- DROPBITS(4) ---// - hold >>>= 4; - bits -= 4; - //---// - len = (hold & 0x0f)/*BITS(4)*/ + 8; - if (state.wbits === 0) { - state.wbits = len; - } - else if (len > state.wbits) { - strm.msg = 'invalid window size'; - state.mode = BAD; - break; - } - state.dmax = 1 << len; - //Tracev((stderr, "inflate: zlib header ok\n")); - strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; - state.mode = hold & 0x200 ? DICTID : TYPE; - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - break; - case FLAGS: - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.flags = hold; - if ((state.flags & 0xff) !== Z_DEFLATED) { - strm.msg = 'unknown compression method'; - state.mode = BAD; - break; - } - if (state.flags & 0xe000) { - strm.msg = 'unknown header flags set'; - state.mode = BAD; - break; - } - if (state.head) { - state.head.text = ((hold >> 8) & 1); - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = TIME; - /* falls through */ - case TIME: - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (state.head) { - state.head.time = hold; - } - if (state.flags & 0x0200) { - //=== CRC4(state.check, hold) - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - hbuf[2] = (hold >>> 16) & 0xff; - hbuf[3] = (hold >>> 24) & 0xff; - state.check = crc32(state.check, hbuf, 4, 0); - //=== - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = OS; - /* falls through */ - case OS: - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (state.head) { - state.head.xflags = (hold & 0xff); - state.head.os = (hold >> 8); - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = EXLEN; - /* falls through */ - case EXLEN: - if (state.flags & 0x0400) { - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.length = hold; - if (state.head) { - state.head.extra_len = hold; - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - } - else if (state.head) { - state.head.extra = null/*Z_NULL*/; - } - state.mode = EXTRA; - /* falls through */ - case EXTRA: - if (state.flags & 0x0400) { - copy = state.length; - if (copy > have) { copy = have; } - if (copy) { - if (state.head) { - len = state.head.extra_len - state.length; - if (!state.head.extra) { - // Use untyped array for more convenient processing later - state.head.extra = new Array(state.head.extra_len); - } - utils.arraySet( - state.head.extra, - input, - next, - // extra field is limited to 65536 bytes - // - no need for additional size check - copy, - /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ - len - ); - //zmemcpy(state.head.extra + len, next, - // len + copy > state.head.extra_max ? - // state.head.extra_max - len : copy); - } - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - state.length -= copy; - } - if (state.length) { break inf_leave; } - } - state.length = 0; - state.mode = NAME; - /* falls through */ - case NAME: - if (state.flags & 0x0800) { - if (have === 0) { break inf_leave; } - copy = 0; - do { - // TODO: 2 or 1 bytes? - len = input[next + copy++]; - /* use constant limit because in js we should not preallocate memory */ - if (state.head && len && - (state.length < 65536 /*state.head.name_max*/)) { - state.head.name += String.fromCharCode(len); - } - } while (len && copy < have); - - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { break inf_leave; } - } - else if (state.head) { - state.head.name = null; - } - state.length = 0; - state.mode = COMMENT; - /* falls through */ - case COMMENT: - if (state.flags & 0x1000) { - if (have === 0) { break inf_leave; } - copy = 0; - do { - len = input[next + copy++]; - /* use constant limit because in js we should not preallocate memory */ - if (state.head && len && - (state.length < 65536 /*state.head.comm_max*/)) { - state.head.comment += String.fromCharCode(len); - } - } while (len && copy < have); - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { break inf_leave; } - } - else if (state.head) { - state.head.comment = null; - } - state.mode = HCRC; - /* falls through */ - case HCRC: - if (state.flags & 0x0200) { - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (hold !== (state.check & 0xffff)) { - strm.msg = 'header crc mismatch'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - } - if (state.head) { - state.head.hcrc = ((state.flags >> 9) & 1); - state.head.done = true; - } - strm.adler = state.check = 0; - state.mode = TYPE; - break; - case DICTID: - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - strm.adler = state.check = zswap32(hold); - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = DICT; - /* falls through */ - case DICT: - if (state.havedict === 0) { - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - return Z_NEED_DICT; - } - strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; - state.mode = TYPE; - /* falls through */ - case TYPE: - if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } - /* falls through */ - case TYPEDO: - if (state.last) { - //--- BYTEBITS() ---// - hold >>>= bits & 7; - bits -= bits & 7; - //---// - state.mode = CHECK; - break; - } - //=== NEEDBITS(3); */ - while (bits < 3) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.last = (hold & 0x01)/*BITS(1)*/; - //--- DROPBITS(1) ---// - hold >>>= 1; - bits -= 1; - //---// - - switch ((hold & 0x03)/*BITS(2)*/) { - case 0: /* stored block */ - //Tracev((stderr, "inflate: stored block%s\n", - // state.last ? " (last)" : "")); - state.mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - //Tracev((stderr, "inflate: fixed codes block%s\n", - // state.last ? " (last)" : "")); - state.mode = LEN_; /* decode codes */ - if (flush === Z_TREES) { - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - break inf_leave; - } - break; - case 2: /* dynamic block */ - //Tracev((stderr, "inflate: dynamic codes block%s\n", - // state.last ? " (last)" : "")); - state.mode = TABLE; - break; - case 3: - strm.msg = 'invalid block type'; - state.mode = BAD; - } - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - break; - case STORED: - //--- BYTEBITS() ---// /* go to byte boundary */ - hold >>>= bits & 7; - bits -= bits & 7; - //---// - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { - strm.msg = 'invalid stored block lengths'; - state.mode = BAD; - break; - } - state.length = hold & 0xffff; - //Tracev((stderr, "inflate: stored length %u\n", - // state.length)); - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = COPY_; - if (flush === Z_TREES) { break inf_leave; } - /* falls through */ - case COPY_: - state.mode = COPY; - /* falls through */ - case COPY: - copy = state.length; - if (copy) { - if (copy > have) { copy = have; } - if (copy > left) { copy = left; } - if (copy === 0) { break inf_leave; } - //--- zmemcpy(put, next, copy); --- - utils.arraySet(output, input, next, copy, put); - //---// - have -= copy; - next += copy; - left -= copy; - put += copy; - state.length -= copy; - break; - } - //Tracev((stderr, "inflate: stored end\n")); - state.mode = TYPE; - break; - case TABLE: - //=== NEEDBITS(14); */ - while (bits < 14) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; - //--- DROPBITS(5) ---// - hold >>>= 5; - bits -= 5; - //---// - state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; - //--- DROPBITS(5) ---// - hold >>>= 5; - bits -= 5; - //---// - state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; - //--- DROPBITS(4) ---// - hold >>>= 4; - bits -= 4; - //---// - //#ifndef PKZIP_BUG_WORKAROUND - if (state.nlen > 286 || state.ndist > 30) { - strm.msg = 'too many length or distance symbols'; - state.mode = BAD; - break; - } - //#endif - //Tracev((stderr, "inflate: table sizes ok\n")); - state.have = 0; - state.mode = LENLENS; - /* falls through */ - case LENLENS: - while (state.have < state.ncode) { - //=== NEEDBITS(3); - while (bits < 3) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); - //--- DROPBITS(3) ---// - hold >>>= 3; - bits -= 3; - //---// - } - while (state.have < 19) { - state.lens[order[state.have++]] = 0; - } - // We have separate tables & no pointers. 2 commented lines below not needed. - //state.next = state.codes; - //state.lencode = state.next; - // Switch to use dynamic table - state.lencode = state.lendyn; - state.lenbits = 7; - - opts = { bits: state.lenbits }; - ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); - state.lenbits = opts.bits; - - if (ret) { - strm.msg = 'invalid code lengths set'; - state.mode = BAD; - break; - } - //Tracev((stderr, "inflate: code lengths ok\n")); - state.have = 0; - state.mode = CODELENS; - /* falls through */ - case CODELENS: - while (state.have < state.nlen + state.ndist) { - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if (here_val < 16) { - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.lens[state.have++] = here_val; - } - else { - if (here_val === 16) { - //=== NEEDBITS(here.bits + 2); - n = here_bits + 2; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - if (state.have === 0) { - strm.msg = 'invalid bit length repeat'; - state.mode = BAD; - break; - } - len = state.lens[state.have - 1]; - copy = 3 + (hold & 0x03);//BITS(2); - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - } - else if (here_val === 17) { - //=== NEEDBITS(here.bits + 3); - n = here_bits + 3; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - len = 0; - copy = 3 + (hold & 0x07);//BITS(3); - //--- DROPBITS(3) ---// - hold >>>= 3; - bits -= 3; - //---// - } - else { - //=== NEEDBITS(here.bits + 7); - n = here_bits + 7; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - len = 0; - copy = 11 + (hold & 0x7f);//BITS(7); - //--- DROPBITS(7) ---// - hold >>>= 7; - bits -= 7; - //---// - } - if (state.have + copy > state.nlen + state.ndist) { - strm.msg = 'invalid bit length repeat'; - state.mode = BAD; - break; - } - while (copy--) { - state.lens[state.have++] = len; - } - } - } - - /* handle error breaks in while */ - if (state.mode === BAD) { break; } - - /* check for end-of-block code (better have one) */ - if (state.lens[256] === 0) { - strm.msg = 'invalid code -- missing end-of-block'; - state.mode = BAD; - break; - } - - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state.lenbits = 9; - - opts = { bits: state.lenbits }; - ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); - // We have separate tables & no pointers. 2 commented lines below not needed. - // state.next_index = opts.table_index; - state.lenbits = opts.bits; - // state.lencode = state.next; - - if (ret) { - strm.msg = 'invalid literal/lengths set'; - state.mode = BAD; - break; - } - - state.distbits = 6; - //state.distcode.copy(state.codes); - // Switch to use dynamic table - state.distcode = state.distdyn; - opts = { bits: state.distbits }; - ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); - // We have separate tables & no pointers. 2 commented lines below not needed. - // state.next_index = opts.table_index; - state.distbits = opts.bits; - // state.distcode = state.next; - - if (ret) { - strm.msg = 'invalid distances set'; - state.mode = BAD; - break; - } - //Tracev((stderr, 'inflate: codes ok\n')); - state.mode = LEN_; - if (flush === Z_TREES) { break inf_leave; } - /* falls through */ - case LEN_: - state.mode = LEN; - /* falls through */ - case LEN: - if (have >= 6 && left >= 258) { - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - inflate_fast(strm, _out); - //--- LOAD() --- - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - //--- - - if (state.mode === TYPE) { - state.back = -1; - } - break; - } - state.back = 0; - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if (here_bits <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if (here_op && (here_op & 0xf0) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.lencode[last_val + - ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((last_bits + here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - //--- DROPBITS(last.bits) ---// - hold >>>= last_bits; - bits -= last_bits; - //---// - state.back += last_bits; - } - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.back += here_bits; - state.length = here_val; - if (here_op === 0) { - //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - // "inflate: literal '%c'\n" : - // "inflate: literal 0x%02x\n", here.val)); - state.mode = LIT; - break; - } - if (here_op & 32) { - //Tracevv((stderr, "inflate: end of block\n")); - state.back = -1; - state.mode = TYPE; - break; - } - if (here_op & 64) { - strm.msg = 'invalid literal/length code'; - state.mode = BAD; - break; - } - state.extra = here_op & 15; - state.mode = LENEXT; - /* falls through */ - case LENEXT: - if (state.extra) { - //=== NEEDBITS(state.extra); - n = state.extra; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; - //--- DROPBITS(state.extra) ---// - hold >>>= state.extra; - bits -= state.extra; - //---// - state.back += state.extra; - } - //Tracevv((stderr, "inflate: length %u\n", state.length)); - state.was = state.length; - state.mode = DIST; - /* falls through */ - case DIST: - for (;;) { - here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if ((here_op & 0xf0) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.distcode[last_val + - ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((last_bits + here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - //--- DROPBITS(last.bits) ---// - hold >>>= last_bits; - bits -= last_bits; - //---// - state.back += last_bits; - } - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.back += here_bits; - if (here_op & 64) { - strm.msg = 'invalid distance code'; - state.mode = BAD; - break; - } - state.offset = here_val; - state.extra = (here_op) & 15; - state.mode = DISTEXT; - /* falls through */ - case DISTEXT: - if (state.extra) { - //=== NEEDBITS(state.extra); - n = state.extra; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; - //--- DROPBITS(state.extra) ---// - hold >>>= state.extra; - bits -= state.extra; - //---// - state.back += state.extra; - } - //#ifdef INFLATE_STRICT - if (state.offset > state.dmax) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break; - } - //#endif - //Tracevv((stderr, "inflate: distance %u\n", state.offset)); - state.mode = MATCH; - /* falls through */ - case MATCH: - if (left === 0) { break inf_leave; } - copy = _out - left; - if (state.offset > copy) { /* copy from window */ - copy = state.offset - copy; - if (copy > state.whave) { - if (state.sane) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break; - } - // (!) This block is disabled in zlib defaults, - // don't enable it for binary compatibility - //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - // Trace((stderr, "inflate.c too far\n")); - // copy -= state.whave; - // if (copy > state.length) { copy = state.length; } - // if (copy > left) { copy = left; } - // left -= copy; - // state.length -= copy; - // do { - // output[put++] = 0; - // } while (--copy); - // if (state.length === 0) { state.mode = LEN; } - // break; - //#endif - } - if (copy > state.wnext) { - copy -= state.wnext; - from = state.wsize - copy; - } - else { - from = state.wnext - copy; - } - if (copy > state.length) { copy = state.length; } - from_source = state.window; - } - else { /* copy from output */ - from_source = output; - from = put - state.offset; - copy = state.length; - } - if (copy > left) { copy = left; } - left -= copy; - state.length -= copy; - do { - output[put++] = from_source[from++]; - } while (--copy); - if (state.length === 0) { state.mode = LEN; } - break; - case LIT: - if (left === 0) { break inf_leave; } - output[put++] = state.length; - left--; - state.mode = LEN; - break; - case CHECK: - if (state.wrap) { - //=== NEEDBITS(32); - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - // Use '|' instead of '+' to make sure that result is signed - hold |= input[next++] << bits; - bits += 8; - } - //===// - _out -= left; - strm.total_out += _out; - state.total += _out; - if (_out) { - strm.adler = state.check = - /*UPDATE(state.check, put - _out, _out);*/ - (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); - - } - _out = left; - // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too - if ((state.flags ? hold : zswap32(hold)) !== state.check) { - strm.msg = 'incorrect data check'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - //Tracev((stderr, "inflate: check matches trailer\n")); - } - state.mode = LENGTH; - /* falls through */ - case LENGTH: - if (state.wrap && state.flags) { - //=== NEEDBITS(32); - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (hold !== (state.total & 0xffffffff)) { - strm.msg = 'incorrect length check'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - //Tracev((stderr, "inflate: length matches trailer\n")); - } - state.mode = DONE; - /* falls through */ - case DONE: - ret = Z_STREAM_END; - break inf_leave; - case BAD: - ret = Z_DATA_ERROR; - break inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - /* falls through */ - default: - return Z_STREAM_ERROR; - } - } - - // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - - if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && - (state.mode < CHECK || flush !== Z_FINISH))) { - if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { - state.mode = MEM; - return Z_MEM_ERROR; - } - } - _in -= strm.avail_in; - _out -= strm.avail_out; - strm.total_in += _in; - strm.total_out += _out; - state.total += _out; - if (state.wrap && _out) { - strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ - (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); - } - strm.data_type = state.bits + (state.last ? 64 : 0) + - (state.mode === TYPE ? 128 : 0) + - (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); - if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { - ret = Z_BUF_ERROR; - } - return ret; - } - - function inflateEnd(strm) { - - if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { - return Z_STREAM_ERROR; - } - - var state = strm.state; - if (state.window) { - state.window = null; - } - strm.state = null; - return Z_OK; - } - - function inflateGetHeader(strm, head) { - var state; - - /* check state */ - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } - - /* save header structure */ - state.head = head; - head.done = false; - return Z_OK; - } - - function inflateSetDictionary(strm, dictionary) { - var dictLength = dictionary.length; - - var state; - var dictid; - var ret; - - /* check state */ - if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; } - state = strm.state; - - if (state.wrap !== 0 && state.mode !== DICT) { - return Z_STREAM_ERROR; - } - - /* check for correct dictionary identifier */ - if (state.mode === DICT) { - dictid = 1; /* adler32(0, null, 0)*/ - /* dictid = adler32(dictid, dictionary, dictLength); */ - dictid = adler32(dictid, dictionary, dictLength, 0); - if (dictid !== state.check) { - return Z_DATA_ERROR; - } - } - /* copy dictionary to window using updatewindow(), which will amend the - existing dictionary if appropriate */ - ret = updatewindow(strm, dictionary, dictLength, dictLength); - if (ret) { - state.mode = MEM; - return Z_MEM_ERROR; - } - state.havedict = 1; - // Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; - } - - exports.inflateReset = inflateReset; - exports.inflateReset2 = inflateReset2; - exports.inflateResetKeep = inflateResetKeep; - exports.inflateInit = inflateInit; - exports.inflateInit2 = inflateInit2; - exports.inflate = inflate; - exports.inflateEnd = inflateEnd; - exports.inflateGetHeader = inflateGetHeader; - exports.inflateSetDictionary = inflateSetDictionary; - exports.inflateInfo = 'pako inflate (from Nodeca project)'; - - /* Not implemented - exports.inflateCopy = inflateCopy; - exports.inflateGetDictionary = inflateGetDictionary; - exports.inflateMark = inflateMark; - exports.inflatePrime = inflatePrime; - exports.inflateSync = inflateSync; - exports.inflateSyncPoint = inflateSyncPoint; - exports.inflateUndermine = inflateUndermine; - */ - - },{"../utils/common":1,"./adler32":3,"./crc32":5,"./inffast":7,"./inftrees":9}],9:[function(require,module,exports){ - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - var utils = require('../utils/common'); - - var MAXBITS = 15; - var ENOUGH_LENS = 852; - var ENOUGH_DISTS = 592; - //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); - - var CODES = 0; - var LENS = 1; - var DISTS = 2; - - var lbase = [ /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 - ]; - - var lext = [ /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 - ]; - - var dbase = [ /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0 - ]; - - var dext = [ /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64 - ]; - - module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) - { - var bits = opts.bits; - //here = opts.here; /* table entry for duplication */ - - var len = 0; /* a code's length in bits */ - var sym = 0; /* index of code symbols */ - var min = 0, max = 0; /* minimum and maximum code lengths */ - var root = 0; /* number of index bits for root table */ - var curr = 0; /* number of index bits for current table */ - var drop = 0; /* code bits to drop for sub-table */ - var left = 0; /* number of prefix codes available */ - var used = 0; /* code entries in table used */ - var huff = 0; /* Huffman code */ - var incr; /* for incrementing code, index */ - var fill; /* index for replicating entries */ - var low; /* low bits for current root entry */ - var mask; /* mask for low root bits */ - var next; /* next available space in table */ - var base = null; /* base value table to use */ - var base_index = 0; - // var shoextra; /* extra bits table to use */ - var end; /* use base and extra for symbol > end */ - var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */ - var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */ - var extra = null; - var extra_index = 0; - - var here_bits, here_op, here_val; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) { - count[len] = 0; - } - for (sym = 0; sym < codes; sym++) { - count[lens[lens_index + sym]]++; - } - - /* bound code lengths, force root to be within code lengths */ - root = bits; - for (max = MAXBITS; max >= 1; max--) { - if (count[max] !== 0) { break; } - } - if (root > max) { - root = max; - } - if (max === 0) { /* no symbols to code at all */ - //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ - //table.bits[opts.table_index] = 1; //here.bits = (var char)1; - //table.val[opts.table_index++] = 0; //here.val = (var short)0; - table[table_index++] = (1 << 24) | (64 << 16) | 0; - - - //table.op[opts.table_index] = 64; - //table.bits[opts.table_index] = 1; - //table.val[opts.table_index++] = 0; - table[table_index++] = (1 << 24) | (64 << 16) | 0; - - opts.bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min < max; min++) { - if (count[min] !== 0) { break; } - } - if (root < min) { - root = min; - } - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) { - return -1; - } /* over-subscribed */ - } - if (left > 0 && (type === CODES || max !== 1)) { - return -1; /* incomplete set */ - } - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) { - offs[len + 1] = offs[len] + count[len]; - } - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) { - if (lens[lens_index + sym] !== 0) { - work[offs[lens[lens_index + sym]]++] = sym; - } - } - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked for LENS and DIST tables against - the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in - the initial root table size constants. See the comments in inftrees.h - for more information. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - // poor man optimization - use if-else instead of switch, - // to avoid deopts in old v8 - if (type === CODES) { - base = extra = work; /* dummy value--not used */ - end = 19; - - } else if (type === LENS) { - base = lbase; - base_index -= 257; - extra = lext; - extra_index -= 257; - end = 256; - - } else { /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize opts for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = table_index; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = -1; /* trigger new sub-table when len > root */ - used = 1 << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if ((type === LENS && used > ENOUGH_LENS) || - (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - here_bits = len - drop; - if (work[sym] < end) { - here_op = 0; - here_val = work[sym]; - } - else if (work[sym] > end) { - here_op = extra[extra_index + work[sym]]; - here_val = base[base_index + work[sym]]; - } - else { - here_op = 32 + 64; /* end of block */ - here_val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1 << (len - drop); - fill = 1 << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; - } while (fill !== 0); - - /* backwards increment the len-bit code huff */ - incr = 1 << (len - 1); - while (huff & incr) { - incr >>= 1; - } - if (incr !== 0) { - huff &= incr - 1; - huff += incr; - } else { - huff = 0; - } - - /* go to next symbol, update count, len */ - sym++; - if (--count[len] === 0) { - if (len === max) { break; } - len = lens[lens_index + work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) !== low) { - /* if first time, transition to sub-tables */ - if (drop === 0) { - drop = root; - } - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = 1 << curr; - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) { break; } - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1 << curr; - if ((type === LENS && used > ENOUGH_LENS) || - (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } - - /* point entry in root table to sub-table */ - low = huff & mask; - /*table.op[low] = curr; - table.bits[low] = root; - table.val[low] = next - opts.table_index;*/ - table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; - } - } - - /* fill in remaining table entry if code is incomplete (guaranteed to have - at most one remaining entry, since if the code is incomplete, the - maximum code length that was allowed to get this far is one bit) */ - if (huff !== 0) { - //table.op[next + huff] = 64; /* invalid code marker */ - //table.bits[next + huff] = len - drop; - //table.val[next + huff] = 0; - table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; - } - - /* set return parameters */ - //opts.table_index += used; - opts.bits = root; - return 0; - }; - - },{"../utils/common":1}],10:[function(require,module,exports){ - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - module.exports = { - 2: 'need dictionary', /* Z_NEED_DICT 2 */ - 1: 'stream end', /* Z_STREAM_END 1 */ - 0: '', /* Z_OK 0 */ - '-1': 'file error', /* Z_ERRNO (-1) */ - '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ - '-3': 'data error', /* Z_DATA_ERROR (-3) */ - '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ - '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ - '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ - }; - - },{}],11:[function(require,module,exports){ - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - function ZStream() { - /* next input byte */ - this.input = null; // JS specific, because we have no pointers - this.next_in = 0; - /* number of bytes available at input */ - this.avail_in = 0; - /* total number of input bytes read so far */ - this.total_in = 0; - /* next output byte should be put there */ - this.output = null; // JS specific, because we have no pointers - this.next_out = 0; - /* remaining free space at output */ - this.avail_out = 0; - /* total number of bytes output so far */ - this.total_out = 0; - /* last error message, NULL if no error */ - this.msg = ''/*Z_NULL*/; - /* not visible by applications */ - this.state = null; - /* best guess about the data type: binary or text */ - this.data_type = 2/*Z_UNKNOWN*/; - /* adler32 value of the uncompressed data */ - this.adler = 0; - } - - module.exports = ZStream; - - },{}],"/lib/inflate.js":[function(require,module,exports){ - 'use strict'; - - - var zlib_inflate = require('./zlib/inflate'); - var utils = require('./utils/common'); - var strings = require('./utils/strings'); - var c = require('./zlib/constants'); - var msg = require('./zlib/messages'); - var ZStream = require('./zlib/zstream'); - var GZheader = require('./zlib/gzheader'); - - var toString = Object.prototype.toString; - - /** - * class Inflate - * - * Generic JS-style wrapper for zlib calls. If you don't need - * streaming behaviour - use more simple functions: [[inflate]] - * and [[inflateRaw]]. - **/ - - /* internal - * inflate.chunks -> Array - * - * Chunks of output data, if [[Inflate#onData]] not overridden. - **/ - - /** - * Inflate.result -> Uint8Array|Array|String - * - * Uncompressed result, generated by default [[Inflate#onData]] - * and [[Inflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you - * push a chunk with explicit flush (call [[Inflate#push]] with - * `Z_SYNC_FLUSH` param). - **/ - - /** - * Inflate.err -> Number - * - * Error code after inflate finished. 0 (Z_OK) on success. - * Should be checked if broken data possible. - **/ - - /** - * Inflate.msg -> String - * - * Error message, if [[Inflate.err]] != 0 - **/ - - - /** - * new Inflate(options) - * - options (Object): zlib inflate options. - * - * Creates new inflator instance with specified params. Throws exception - * on bad params. Supported options: - * - * - `windowBits` - * - `dictionary` - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Additional options, for internal needs: - * - * - `chunkSize` - size of generated data chunks (16K by default) - * - `raw` (Boolean) - do raw inflate - * - `to` (String) - if equal to 'string', then result will be converted - * from utf8 to utf16 (javascript) string. When string output requested, - * chunk length can differ from `chunkSize`, depending on content. - * - * By default, when no options set, autodetect deflate/gzip data format via - * wrapper header. - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) - * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); - * - * var inflate = new pako.Inflate({ level: 3}); - * - * inflate.push(chunk1, false); - * inflate.push(chunk2, true); // true -> last chunk - * - * if (inflate.err) { throw new Error(inflate.err); } - * - * console.log(inflate.result); - * ``` - **/ - function Inflate(options) { - if (!(this instanceof Inflate)) return new Inflate(options); - - this.options = utils.assign({ - chunkSize: 16384, - windowBits: 0, - to: '' - }, options || {}); - - var opt = this.options; - - // Force window size for `raw` data, if not set directly, - // because we have no header for autodetect. - if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { - opt.windowBits = -opt.windowBits; - if (opt.windowBits === 0) { opt.windowBits = -15; } - } - - // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate - if ((opt.windowBits >= 0) && (opt.windowBits < 16) && - !(options && options.windowBits)) { - opt.windowBits += 32; - } - - // Gzip header has no info about windows size, we can do autodetect only - // for deflate. So, if window size not set, force it to max when gzip possible - if ((opt.windowBits > 15) && (opt.windowBits < 48)) { - // bit 3 (16) -> gzipped data - // bit 4 (32) -> autodetect gzip/deflate - if ((opt.windowBits & 15) === 0) { - opt.windowBits |= 15; - } - } - - this.err = 0; // error code, if happens (0 = Z_OK) - this.msg = ''; // error message - this.ended = false; // used to avoid multiple onEnd() calls - this.chunks = []; // chunks of compressed data - - this.strm = new ZStream(); - this.strm.avail_out = 0; - - var status = zlib_inflate.inflateInit2( - this.strm, - opt.windowBits - ); - - if (status !== c.Z_OK) { - throw new Error(msg[status]); - } - - this.header = new GZheader(); - - zlib_inflate.inflateGetHeader(this.strm, this.header); - - // Setup dictionary - if (opt.dictionary) { - // Convert data if needed - if (typeof opt.dictionary === 'string') { - opt.dictionary = strings.string2buf(opt.dictionary); - } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') { - opt.dictionary = new Uint8Array(opt.dictionary); - } - if (opt.raw) { //In raw mode we need to set the dictionary early - status = zlib_inflate.inflateSetDictionary(this.strm, opt.dictionary); - if (status !== c.Z_OK) { - throw new Error(msg[status]); - } - } - } - } - - /** - * Inflate#push(data[, mode]) -> Boolean - * - data (Uint8Array|Array|ArrayBuffer|String): input data - * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. - * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. - * - * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with - * new output chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That will flush internal pending buffers and call - * [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you - * can use mode Z_SYNC_FLUSH, keeping the decompression context. - * - * On fail call [[Inflate#onEnd]] with error code and return false. - * - * We strongly recommend to use `Uint8Array` on input for best speed (output - * format is detected automatically). Also, don't skip last param and always - * use the same type in your code (boolean or number). That will improve JS speed. - * - * For regular `Array`-s make sure all elements are [0..255]. - * - * ##### Example - * - * ```javascript - * push(chunk, false); // push one of data chunks - * ... - * push(chunk, true); // push last chunk - * ``` - **/ - Inflate.prototype.push = function (data, mode) { - var strm = this.strm; - var chunkSize = this.options.chunkSize; - var dictionary = this.options.dictionary; - var status, _mode; - var next_out_utf8, tail, utf8str; - - // Flag to properly process Z_BUF_ERROR on testing inflate call - // when we check that all output data was flushed. - var allowBufError = false; - - if (this.ended) { return false; } - _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH); - - // Convert data if needed - if (typeof data === 'string') { - // Only binary strings can be decompressed on practice - strm.input = strings.binstring2buf(data); - } else if (toString.call(data) === '[object ArrayBuffer]') { - strm.input = new Uint8Array(data); - } else { - strm.input = data; - } - - strm.next_in = 0; - strm.avail_in = strm.input.length; - - do { - if (strm.avail_out === 0) { - strm.output = new utils.Buf8(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } - - status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */ - - if (status === c.Z_NEED_DICT && dictionary) { - status = zlib_inflate.inflateSetDictionary(this.strm, dictionary); - } - - if (status === c.Z_BUF_ERROR && allowBufError === true) { - status = c.Z_OK; - allowBufError = false; - } - - if (status !== c.Z_STREAM_END && status !== c.Z_OK) { - this.onEnd(status); - this.ended = true; - return false; - } - - if (strm.next_out) { - if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) { - - if (this.options.to === 'string') { - - next_out_utf8 = strings.utf8border(strm.output, strm.next_out); - - tail = strm.next_out - next_out_utf8; - utf8str = strings.buf2string(strm.output, next_out_utf8); - - // move tail - strm.next_out = tail; - strm.avail_out = chunkSize - tail; - if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); } - - this.onData(utf8str); - - } else { - this.onData(utils.shrinkBuf(strm.output, strm.next_out)); - } - } - } - - // When no more input data, we should check that internal inflate buffers - // are flushed. The only way to do it when avail_out = 0 - run one more - // inflate pass. But if output data not exists, inflate return Z_BUF_ERROR. - // Here we set flag to process this error properly. - // - // NOTE. Deflate does not return error in this case and does not needs such - // logic. - if (strm.avail_in === 0 && strm.avail_out === 0) { - allowBufError = true; - } - - } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END); - - if (status === c.Z_STREAM_END) { - _mode = c.Z_FINISH; - } - - // Finalize on the last chunk. - if (_mode === c.Z_FINISH) { - status = zlib_inflate.inflateEnd(this.strm); - this.onEnd(status); - this.ended = true; - return status === c.Z_OK; - } - - // callback interim results if Z_SYNC_FLUSH. - if (_mode === c.Z_SYNC_FLUSH) { - this.onEnd(c.Z_OK); - strm.avail_out = 0; - return true; - } - - return true; - }; - - - /** - * Inflate#onData(chunk) -> Void - * - chunk (Uint8Array|Array|String): output data. Type of array depends - * on js engine support. When string output requested, each chunk - * will be string. - * - * By default, stores data blocks in `chunks[]` property and glue - * those in `onEnd`. Override this handler, if you need another behaviour. - **/ - Inflate.prototype.onData = function (chunk) { - this.chunks.push(chunk); - }; - - - /** - * Inflate#onEnd(status) -> Void - * - status (Number): inflate status. 0 (Z_OK) on success, - * other if not. - * - * Called either after you tell inflate that the input stream is - * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH) - * or if an error happened. By default - join collected chunks, - * free memory and fill `results` / `err` properties. - **/ - Inflate.prototype.onEnd = function (status) { - // On success - join - if (status === c.Z_OK) { - if (this.options.to === 'string') { - // Glue & convert here, until we teach pako to send - // utf8 aligned strings to onData - this.result = this.chunks.join(''); - } else { - this.result = utils.flattenChunks(this.chunks); - } - } - this.chunks = []; - this.err = status; - this.msg = this.strm.msg; - }; - - - /** - * inflate(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * Decompress `data` with inflate/ungzip and `options`. Autodetect - * format via wrapper header by default. That's why we don't provide - * separate `ungzip` method. - * - * Supported options are: - * - * - windowBits - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information. - * - * Sugar (options): - * - * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify - * negative windowBits implicitly. - * - `to` (String) - if equal to 'string', then result will be converted - * from utf8 to utf16 (javascript) string. When string output requested, - * chunk length can differ from `chunkSize`, depending on content. - * - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) - * , output; - * - * try { - * output = pako.inflate(input); - * } catch (err) - * console.log(err); - * } - * ``` - **/ - function inflate(input, options) { - var inflator = new Inflate(options); - - inflator.push(input, true); - - // That will never happens, if you don't cheat with options :) - if (inflator.err) { throw inflator.msg || msg[inflator.err]; } - - return inflator.result; - } - - - /** - * inflateRaw(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * The same as [[inflate]], but creates raw data, without wrapper - * (header and adler32 crc). - **/ - function inflateRaw(input, options) { - options = options || {}; - options.raw = true; - return inflate(input, options); - } - - - /** - * ungzip(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * Just shortcut to [[inflate]], because it autodetects format - * by header.content. Done for convenience. - **/ - - - exports.Inflate = Inflate; - exports.inflate = inflate; - exports.inflateRaw = inflateRaw; - exports.ungzip = inflate; - - },{"./utils/common":1,"./utils/strings":2,"./zlib/constants":4,"./zlib/gzheader":6,"./zlib/inflate":8,"./zlib/messages":10,"./zlib/zstream":11}]},{},[])("/lib/inflate.js") - }); -/* eslint-enable */ diff --git a/packages/edit-site/lib/unbrotli.js b/packages/edit-site/lib/unbrotli.js deleted file mode 100644 index 63293e6cc473cf..00000000000000 --- a/packages/edit-site/lib/unbrotli.js +++ /dev/null @@ -1,2039 +0,0 @@ -/** - * Credits: - * - * lib-font - * https://github.com/Pomax/lib-font - * https://github.com/Pomax/lib-font/blob/master/lib/unbrotli.js - * - * The MIT License (MIT) - * - * Copyright (c) 2020 pomax@nihongoresources.com - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint eslint-comments/no-unlimited-disable: 0 */ -/* eslint-disable */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.unbrotli = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0; -}; - -/* Fills up the input ringbuffer by calling the input callback. - - Does nothing if there are at least 32 bytes present after current position. - - Returns 0 if either: - - the input callback returned an error, or - - there is no more input and the position is past the end of the stream. - - After encountering the end of the input stream, 32 additional zero bytes are - copied to the ringbuffer, therefore it is safe to call this function after - every 32 bytes of input is read. -*/ -BrotliBitReader.prototype.readMoreInput = function() { - if (this.bit_end_pos_ > 256) { - return; - } else if (this.eos_) { - if (this.bit_pos_ > this.bit_end_pos_) - throw new Error('Unexpected end of input ' + this.bit_pos_ + ' ' + this.bit_end_pos_); - } else { - var dst = this.buf_ptr_; - var bytes_read = this.input_.read(this.buf_, dst, BROTLI_READ_SIZE); - if (bytes_read < 0) { - throw new Error('Unexpected end of input'); - } - - if (bytes_read < BROTLI_READ_SIZE) { - this.eos_ = 1; - /* Store 32 bytes of zero after the stream end. */ - for (var p = 0; p < 32; p++) - this.buf_[dst + bytes_read + p] = 0; - } - - if (dst === 0) { - /* Copy the head of the ringbuffer to the slack region. */ - for (var p = 0; p < 32; p++) - this.buf_[(BROTLI_READ_SIZE << 1) + p] = this.buf_[p]; - - this.buf_ptr_ = BROTLI_READ_SIZE; - } else { - this.buf_ptr_ = 0; - } - - this.bit_end_pos_ += bytes_read << 3; - } -}; - -/* Guarantees that there are at least 24 bits in the buffer. */ -BrotliBitReader.prototype.fillBitWindow = function() { - while (this.bit_pos_ >= 8) { - this.val_ >>>= 8; - this.val_ |= this.buf_[this.pos_ & BROTLI_IBUF_MASK] << 24; - ++this.pos_; - this.bit_pos_ = this.bit_pos_ - 8 >>> 0; - this.bit_end_pos_ = this.bit_end_pos_ - 8 >>> 0; - } -}; - -/* Reads the specified number of bits from Read Buffer. */ -BrotliBitReader.prototype.readBits = function(n_bits) { - if (32 - this.bit_pos_ < n_bits) { - this.fillBitWindow(); - } - - var val = ((this.val_ >>> this.bit_pos_) & kBitMask[n_bits]); - this.bit_pos_ += n_bits; - return val; -}; - -module.exports = BrotliBitReader; - -},{}],2:[function(require,module,exports){ -/* Copyright 2013 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Lookup table to map the previous two bytes to a context id. - - There are four different context modeling modes defined here: - CONTEXT_LSB6: context id is the least significant 6 bits of the last byte, - CONTEXT_MSB6: context id is the most significant 6 bits of the last byte, - CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text, - CONTEXT_SIGNED: second-order context model tuned for signed integers. - - The context id for the UTF8 context model is calculated as follows. If p1 - and p2 are the previous two bytes, we calcualte the context as - - context = kContextLookup[p1] | kContextLookup[p2 + 256]. - - If the previous two bytes are ASCII characters (i.e. < 128), this will be - equivalent to - - context = 4 * context1(p1) + context2(p2), - - where context1 is based on the previous byte in the following way: - - 0 : non-ASCII control - 1 : \t, \n, \r - 2 : space - 3 : other punctuation - 4 : " ' - 5 : % - 6 : ( < [ { - 7 : ) > ] } - 8 : , ; : - 9 : . - 10 : = - 11 : number - 12 : upper-case vowel - 13 : upper-case consonant - 14 : lower-case vowel - 15 : lower-case consonant - - and context2 is based on the second last byte: - - 0 : control, space - 1 : punctuation - 2 : upper-case letter, number - 3 : lower-case letter - - If the last byte is ASCII, and the second last byte is not (in a valid UTF8 - stream it will be a continuation byte, value between 128 and 191), the - context is the same as if the second last byte was an ASCII control or space. - - If the last byte is a UTF8 lead byte (value >= 192), then the next byte will - be a continuation byte and the context id is 2 or 3 depending on the LSB of - the last byte and to a lesser extent on the second last byte if it is ASCII. - - If the last byte is a UTF8 continuation byte, the second last byte can be: - - continuation byte: the next byte is probably ASCII or lead byte (assuming - 4-byte UTF8 characters are rare) and the context id is 0 or 1. - - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1 - - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3 - - The possible value combinations of the previous two bytes, the range of - context ids and the type of the next byte is summarized in the table below: - - |--------\-----------------------------------------------------------------| - | \ Last byte | - | Second \---------------------------------------------------------------| - | last byte \ ASCII | cont. byte | lead byte | - | \ (0-127) | (128-191) | (192-) | - |=============|===================|=====================|==================| - | ASCII | next: ASCII/lead | not valid | next: cont. | - | (0-127) | context: 4 - 63 | | context: 2 - 3 | - |-------------|-------------------|---------------------|------------------| - | cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. | - | (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 | - |-------------|-------------------|---------------------|------------------| - | lead byte | not valid | next: ASCII/lead | not valid | - | (192-207) | | context: 0 - 1 | | - |-------------|-------------------|---------------------|------------------| - | lead byte | not valid | next: cont. | not valid | - | (208-) | | context: 2 - 3 | | - |-------------|-------------------|---------------------|------------------| - - The context id for the signed context mode is calculated as: - - context = (kContextLookup[512 + p1] << 3) | kContextLookup[512 + p2]. - - For any context modeling modes, the context ids can be calculated by |-ing - together two lookups from one table using context model dependent offsets: - - context = kContextLookup[offset1 + p1] | kContextLookup[offset2 + p2]. - - where offset1 and offset2 are dependent on the context mode. -*/ - -var CONTEXT_LSB6 = 0; -var CONTEXT_MSB6 = 1; -var CONTEXT_UTF8 = 2; -var CONTEXT_SIGNED = 3; - -/* Common context lookup table for all context modes. */ -exports.lookup = new Uint8Array([ - /* CONTEXT_UTF8, last byte. */ - /* ASCII range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12, - 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, - 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, - 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, - 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, - /* UTF8 continuation byte range. */ - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - /* UTF8 lead byte range. */ - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - /* CONTEXT_UTF8 second last byte. */ - /* ASCII range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, - /* UTF8 continuation byte range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* UTF8 lead byte range. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - /* CONTEXT_SIGNED, second last byte. */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, - /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */ - 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, - /* CONTEXT_LSB6, last byte. */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - /* CONTEXT_MSB6, last byte. */ - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, - 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, - 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, - 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, - 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, - 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, - 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, - 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, - 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, - 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, - 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, - 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, - 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, - 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, - 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, - /* CONTEXT_{M,L}SB6, second last byte, */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]); - -exports.lookupOffsets = new Uint16Array([ - /* CONTEXT_LSB6 */ - 1024, 1536, - /* CONTEXT_MSB6 */ - 1280, 1536, - /* CONTEXT_UTF8 */ - 0, 256, - /* CONTEXT_SIGNED */ - 768, 512, -]); - -},{}],3:[function(require,module,exports){ -/* Copyright 2013 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -var BrotliInput = require('./streams').BrotliInput; -var BrotliOutput = require('./streams').BrotliOutput; -var BrotliBitReader = require('./bit_reader'); -var BrotliDictionary = require('./dictionary'); -var HuffmanCode = require('./huffman').HuffmanCode; -var BrotliBuildHuffmanTable = require('./huffman').BrotliBuildHuffmanTable; -var Context = require('./context'); -var Prefix = require('./prefix'); -var Transform = require('./transform'); - -var kDefaultCodeLength = 8; -var kCodeLengthRepeatCode = 16; -var kNumLiteralCodes = 256; -var kNumInsertAndCopyCodes = 704; -var kNumBlockLengthCodes = 26; -var kLiteralContextBits = 6; -var kDistanceContextBits = 2; - -var HUFFMAN_TABLE_BITS = 8; -var HUFFMAN_TABLE_MASK = 0xff; -/* Maximum possible Huffman table size for an alphabet size of 704, max code - * length 15 and root table bits 8. */ -var HUFFMAN_MAX_TABLE_SIZE = 1080; - -var CODE_LENGTH_CODES = 18; -var kCodeLengthCodeOrder = new Uint8Array([ - 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15, -]); - -var NUM_DISTANCE_SHORT_CODES = 16; -var kDistanceShortCodeIndexOffset = new Uint8Array([ - 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 -]); - -var kDistanceShortCodeValueOffset = new Int8Array([ - 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 -]); - -var kMaxHuffmanTableSize = new Uint16Array([ - 256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822, - 854, 886, 920, 952, 984, 1016, 1048, 1080 -]); - -function DecodeWindowBits(br) { - var n; - if (br.readBits(1) === 0) { - return 16; - } - - n = br.readBits(3); - if (n > 0) { - return 17 + n; - } - - n = br.readBits(3); - if (n > 0) { - return 8 + n; - } - - return 17; -} - -/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */ -function DecodeVarLenUint8(br) { - if (br.readBits(1)) { - var nbits = br.readBits(3); - if (nbits === 0) { - return 1; - } else { - return br.readBits(nbits) + (1 << nbits); - } - } - return 0; -} - -function MetaBlockLength() { - this.meta_block_length = 0; - this.input_end = 0; - this.is_uncompressed = 0; - this.is_metadata = false; -} - -function DecodeMetaBlockLength(br) { - var out = new MetaBlockLength; - var size_nibbles; - var size_bytes; - var i; - - out.input_end = br.readBits(1); - if (out.input_end && br.readBits(1)) { - return out; - } - - size_nibbles = br.readBits(2) + 4; - if (size_nibbles === 7) { - out.is_metadata = true; - - if (br.readBits(1) !== 0) - throw new Error('Invalid reserved bit'); - - size_bytes = br.readBits(2); - if (size_bytes === 0) - return out; - - for (i = 0; i < size_bytes; i++) { - var next_byte = br.readBits(8); - if (i + 1 === size_bytes && size_bytes > 1 && next_byte === 0) - throw new Error('Invalid size byte'); - - out.meta_block_length |= next_byte << (i * 8); - } - } else { - for (i = 0; i < size_nibbles; ++i) { - var next_nibble = br.readBits(4); - if (i + 1 === size_nibbles && size_nibbles > 4 && next_nibble === 0) - throw new Error('Invalid size nibble'); - - out.meta_block_length |= next_nibble << (i * 4); - } - } - - ++out.meta_block_length; - - if (!out.input_end && !out.is_metadata) { - out.is_uncompressed = br.readBits(1); - } - - return out; -} - -/* Decodes the next Huffman code from bit-stream. */ -function ReadSymbol(table, index, br) { - var start_index = index; - - var nbits; - br.fillBitWindow(); - index += (br.val_ >>> br.bit_pos_) & HUFFMAN_TABLE_MASK; - nbits = table[index].bits - HUFFMAN_TABLE_BITS; - if (nbits > 0) { - br.bit_pos_ += HUFFMAN_TABLE_BITS; - index += table[index].value; - index += (br.val_ >>> br.bit_pos_) & ((1 << nbits) - 1); - } - br.bit_pos_ += table[index].bits; - return table[index].value; -} - -function ReadHuffmanCodeLengths(code_length_code_lengths, num_symbols, code_lengths, br) { - var symbol = 0; - var prev_code_len = kDefaultCodeLength; - var repeat = 0; - var repeat_code_len = 0; - var space = 32768; - - var table = []; - for (var i = 0; i < 32; i++) - table.push(new HuffmanCode(0, 0)); - - BrotliBuildHuffmanTable(table, 0, 5, code_length_code_lengths, CODE_LENGTH_CODES); - - while (symbol < num_symbols && space > 0) { - var p = 0; - var code_len; - - br.readMoreInput(); - br.fillBitWindow(); - p += (br.val_ >>> br.bit_pos_) & 31; - br.bit_pos_ += table[p].bits; - code_len = table[p].value & 0xff; - if (code_len < kCodeLengthRepeatCode) { - repeat = 0; - code_lengths[symbol++] = code_len; - if (code_len !== 0) { - prev_code_len = code_len; - space -= 32768 >> code_len; - } - } else { - var extra_bits = code_len - 14; - var old_repeat; - var repeat_delta; - var new_len = 0; - if (code_len === kCodeLengthRepeatCode) { - new_len = prev_code_len; - } - if (repeat_code_len !== new_len) { - repeat = 0; - repeat_code_len = new_len; - } - old_repeat = repeat; - if (repeat > 0) { - repeat -= 2; - repeat <<= extra_bits; - } - repeat += br.readBits(extra_bits) + 3; - repeat_delta = repeat - old_repeat; - if (symbol + repeat_delta > num_symbols) { - throw new Error('[ReadHuffmanCodeLengths] symbol + repeat_delta > num_symbols'); - } - - for (var x = 0; x < repeat_delta; x++) - code_lengths[symbol + x] = repeat_code_len; - - symbol += repeat_delta; - - if (repeat_code_len !== 0) { - space -= repeat_delta << (15 - repeat_code_len); - } - } - } - if (space !== 0) { - throw new Error("[ReadHuffmanCodeLengths] space = " + space); - } - - for (; symbol < num_symbols; symbol++) - code_lengths[symbol] = 0; -} - -function ReadHuffmanCode(alphabet_size, tables, table, br) { - var table_size = 0; - var simple_code_or_skip; - var code_lengths = new Uint8Array(alphabet_size); - - br.readMoreInput(); - - /* simple_code_or_skip is used as follows: - 1 for simple code; - 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */ - simple_code_or_skip = br.readBits(2); - if (simple_code_or_skip === 1) { - /* Read symbols, codes & code lengths directly. */ - var i; - var max_bits_counter = alphabet_size - 1; - var max_bits = 0; - var symbols = new Int32Array(4); - var num_symbols = br.readBits(2) + 1; - while (max_bits_counter) { - max_bits_counter >>= 1; - ++max_bits; - } - - for (i = 0; i < num_symbols; ++i) { - symbols[i] = br.readBits(max_bits) % alphabet_size; - code_lengths[symbols[i]] = 2; - } - code_lengths[symbols[0]] = 1; - switch (num_symbols) { - case 1: - break; - case 3: - if ((symbols[0] === symbols[1]) || - (symbols[0] === symbols[2]) || - (symbols[1] === symbols[2])) { - throw new Error('[ReadHuffmanCode] invalid symbols'); - } - break; - case 2: - if (symbols[0] === symbols[1]) { - throw new Error('[ReadHuffmanCode] invalid symbols'); - } - - code_lengths[symbols[1]] = 1; - break; - case 4: - if ((symbols[0] === symbols[1]) || - (symbols[0] === symbols[2]) || - (symbols[0] === symbols[3]) || - (symbols[1] === symbols[2]) || - (symbols[1] === symbols[3]) || - (symbols[2] === symbols[3])) { - throw new Error('[ReadHuffmanCode] invalid symbols'); - } - - if (br.readBits(1)) { - code_lengths[symbols[2]] = 3; - code_lengths[symbols[3]] = 3; - } else { - code_lengths[symbols[0]] = 2; - } - break; - } - } else { /* Decode Huffman-coded code lengths. */ - var i; - var code_length_code_lengths = new Uint8Array(CODE_LENGTH_CODES); - var space = 32; - var num_codes = 0; - /* Static Huffman code for the code length code lengths */ - var huff = [ - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 1), - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 5) - ]; - for (i = simple_code_or_skip; i < CODE_LENGTH_CODES && space > 0; ++i) { - var code_len_idx = kCodeLengthCodeOrder[i]; - var p = 0; - var v; - br.fillBitWindow(); - p += (br.val_ >>> br.bit_pos_) & 15; - br.bit_pos_ += huff[p].bits; - v = huff[p].value; - code_length_code_lengths[code_len_idx] = v; - if (v !== 0) { - space -= (32 >> v); - ++num_codes; - } - } - - if (!(num_codes === 1 || space === 0)) - throw new Error('[ReadHuffmanCode] invalid num_codes or space'); - - ReadHuffmanCodeLengths(code_length_code_lengths, alphabet_size, code_lengths, br); - } - - table_size = BrotliBuildHuffmanTable(tables, table, HUFFMAN_TABLE_BITS, code_lengths, alphabet_size); - - if (table_size === 0) { - throw new Error("[ReadHuffmanCode] BuildHuffmanTable failed: "); - } - - return table_size; -} - -function ReadBlockLength(table, index, br) { - var code; - var nbits; - code = ReadSymbol(table, index, br); - nbits = Prefix.kBlockLengthPrefixCode[code].nbits; - return Prefix.kBlockLengthPrefixCode[code].offset + br.readBits(nbits); -} - -function TranslateShortCodes(code, ringbuffer, index) { - var val; - if (code < NUM_DISTANCE_SHORT_CODES) { - index += kDistanceShortCodeIndexOffset[code]; - index &= 3; - val = ringbuffer[index] + kDistanceShortCodeValueOffset[code]; - } else { - val = code - NUM_DISTANCE_SHORT_CODES + 1; - } - return val; -} - -function MoveToFront(v, index) { - var value = v[index]; - var i = index; - for (; i; --i) v[i] = v[i - 1]; - v[0] = value; -} - -function InverseMoveToFrontTransform(v, v_len) { - var mtf = new Uint8Array(256); - var i; - for (i = 0; i < 256; ++i) { - mtf[i] = i; - } - for (i = 0; i < v_len; ++i) { - var index = v[i]; - v[i] = mtf[index]; - if (index) MoveToFront(mtf, index); - } -} - -/* Contains a collection of huffman trees with the same alphabet size. */ -function HuffmanTreeGroup(alphabet_size, num_htrees) { - this.alphabet_size = alphabet_size; - this.num_htrees = num_htrees; - this.codes = new Array(num_htrees + num_htrees * kMaxHuffmanTableSize[(alphabet_size + 31) >>> 5]); - this.htrees = new Uint32Array(num_htrees); -} - -HuffmanTreeGroup.prototype.decode = function(br) { - var i; - var table_size; - var next = 0; - for (i = 0; i < this.num_htrees; ++i) { - this.htrees[i] = next; - table_size = ReadHuffmanCode(this.alphabet_size, this.codes, next, br); - next += table_size; - } -}; - -function DecodeContextMap(context_map_size, br) { - var out = { num_htrees: null, context_map: null }; - var use_rle_for_zeros; - var max_run_length_prefix = 0; - var table; - var i; - - br.readMoreInput(); - var num_htrees = out.num_htrees = DecodeVarLenUint8(br) + 1; - - var context_map = out.context_map = new Uint8Array(context_map_size); - if (num_htrees <= 1) { - return out; - } - - use_rle_for_zeros = br.readBits(1); - if (use_rle_for_zeros) { - max_run_length_prefix = br.readBits(4) + 1; - } - - table = []; - for (i = 0; i < HUFFMAN_MAX_TABLE_SIZE; i++) { - table[i] = new HuffmanCode(0, 0); - } - - ReadHuffmanCode(num_htrees + max_run_length_prefix, table, 0, br); - - for (i = 0; i < context_map_size;) { - var code; - - br.readMoreInput(); - code = ReadSymbol(table, 0, br); - if (code === 0) { - context_map[i] = 0; - ++i; - } else if (code <= max_run_length_prefix) { - var reps = 1 + (1 << code) + br.readBits(code); - while (--reps) { - if (i >= context_map_size) { - throw new Error("[DecodeContextMap] i >= context_map_size"); - } - context_map[i] = 0; - ++i; - } - } else { - context_map[i] = code - max_run_length_prefix; - ++i; - } - } - if (br.readBits(1)) { - InverseMoveToFrontTransform(context_map, context_map_size); - } - - return out; -} - -function DecodeBlockType(max_block_type, trees, tree_type, block_types, ringbuffers, indexes, br) { - var ringbuffer = tree_type * 2; - var index = tree_type; - var type_code = ReadSymbol(trees, tree_type * HUFFMAN_MAX_TABLE_SIZE, br); - var block_type; - if (type_code === 0) { - block_type = ringbuffers[ringbuffer + (indexes[index] & 1)]; - } else if (type_code === 1) { - block_type = ringbuffers[ringbuffer + ((indexes[index] - 1) & 1)] + 1; - } else { - block_type = type_code - 2; - } - if (block_type >= max_block_type) { - block_type -= max_block_type; - } - block_types[tree_type] = block_type; - ringbuffers[ringbuffer + (indexes[index] & 1)] = block_type; - ++indexes[index]; -} - -function CopyUncompressedBlockToOutput(output, len, pos, ringbuffer, ringbuffer_mask, br) { - var rb_size = ringbuffer_mask + 1; - var rb_pos = pos & ringbuffer_mask; - var br_pos = br.pos_ & BrotliBitReader.IBUF_MASK; - var nbytes; - - /* For short lengths copy byte-by-byte */ - if (len < 8 || br.bit_pos_ + (len << 3) < br.bit_end_pos_) { - while (len-- > 0) { - br.readMoreInput(); - ringbuffer[rb_pos++] = br.readBits(8); - if (rb_pos === rb_size) { - output.write(ringbuffer, rb_size); - rb_pos = 0; - } - } - return; - } - - if (br.bit_end_pos_ < 32) { - throw new Error('[CopyUncompressedBlockToOutput] br.bit_end_pos_ < 32'); - } - - /* Copy remaining 0-4 bytes from br.val_ to ringbuffer. */ - while (br.bit_pos_ < 32) { - ringbuffer[rb_pos] = (br.val_ >>> br.bit_pos_); - br.bit_pos_ += 8; - ++rb_pos; - --len; - } - - /* Copy remaining bytes from br.buf_ to ringbuffer. */ - nbytes = (br.bit_end_pos_ - br.bit_pos_) >> 3; - if (br_pos + nbytes > BrotliBitReader.IBUF_MASK) { - var tail = BrotliBitReader.IBUF_MASK + 1 - br_pos; - for (var x = 0; x < tail; x++) - ringbuffer[rb_pos + x] = br.buf_[br_pos + x]; - - nbytes -= tail; - rb_pos += tail; - len -= tail; - br_pos = 0; - } - - for (var x = 0; x < nbytes; x++) - ringbuffer[rb_pos + x] = br.buf_[br_pos + x]; - - rb_pos += nbytes; - len -= nbytes; - - /* If we wrote past the logical end of the ringbuffer, copy the tail of the - ringbuffer to its beginning and flush the ringbuffer to the output. */ - if (rb_pos >= rb_size) { - output.write(ringbuffer, rb_size); - rb_pos -= rb_size; - for (var x = 0; x < rb_pos; x++) - ringbuffer[x] = ringbuffer[rb_size + x]; - } - - /* If we have more to copy than the remaining size of the ringbuffer, then we - first fill the ringbuffer from the input and then flush the ringbuffer to - the output */ - while (rb_pos + len >= rb_size) { - nbytes = rb_size - rb_pos; - if (br.input_.read(ringbuffer, rb_pos, nbytes) < nbytes) { - throw new Error('[CopyUncompressedBlockToOutput] not enough bytes'); - } - output.write(ringbuffer, rb_size); - len -= nbytes; - rb_pos = 0; - } - - /* Copy straight from the input onto the ringbuffer. The ringbuffer will be - flushed to the output at a later time. */ - if (br.input_.read(ringbuffer, rb_pos, len) < len) { - throw new Error('[CopyUncompressedBlockToOutput] not enough bytes'); - } - - /* Restore the state of the bit reader. */ - br.reset(); -} - -/* Advances the bit reader position to the next byte boundary and verifies - that any skipped bits are set to zero. */ -function JumpToByteBoundary(br) { - var new_bit_pos = (br.bit_pos_ + 7) & ~7; - var pad_bits = br.readBits(new_bit_pos - br.bit_pos_); - return pad_bits == 0; -} - -function BrotliDecompressedSize(buffer) { - var input = new BrotliInput(buffer); - var br = new BrotliBitReader(input); - DecodeWindowBits(br); - var out = DecodeMetaBlockLength(br); - return out.meta_block_length; -} - -exports.BrotliDecompressedSize = BrotliDecompressedSize; - -function BrotliDecompressBuffer(buffer, output_size) { - var input = new BrotliInput(buffer); - - if (output_size == null) { - output_size = BrotliDecompressedSize(buffer); - } - - var output_buffer = new Uint8Array(output_size); - var output = new BrotliOutput(output_buffer); - - BrotliDecompress(input, output); - - if (output.pos < output.buffer.length) { - output.buffer = output.buffer.subarray(0, output.pos); - } - - return output.buffer; -} - -exports.BrotliDecompressBuffer = BrotliDecompressBuffer; - -function BrotliDecompress(input, output) { - var i; - var pos = 0; - var input_end = 0; - var window_bits = 0; - var max_backward_distance; - var max_distance = 0; - var ringbuffer_size; - var ringbuffer_mask; - var ringbuffer; - var ringbuffer_end; - /* This ring buffer holds a few past copy distances that will be used by */ - /* some special distance codes. */ - var dist_rb = [ 16, 15, 11, 4 ]; - var dist_rb_idx = 0; - /* The previous 2 bytes used for context. */ - var prev_byte1 = 0; - var prev_byte2 = 0; - var hgroup = [new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0)]; - var block_type_trees; - var block_len_trees; - var br; - - /* We need the slack region for the following reasons: - - always doing two 8-byte copies for fast backward copying - - transforms - - flushing the input ringbuffer when decoding uncompressed blocks */ - var kRingBufferWriteAheadSlack = 128 + BrotliBitReader.READ_SIZE; - - br = new BrotliBitReader(input); - - /* Decode window size. */ - window_bits = DecodeWindowBits(br); - max_backward_distance = (1 << window_bits) - 16; - - ringbuffer_size = 1 << window_bits; - ringbuffer_mask = ringbuffer_size - 1; - ringbuffer = new Uint8Array(ringbuffer_size + kRingBufferWriteAheadSlack + BrotliDictionary.maxDictionaryWordLength); - ringbuffer_end = ringbuffer_size; - - block_type_trees = []; - block_len_trees = []; - for (var x = 0; x < 3 * HUFFMAN_MAX_TABLE_SIZE; x++) { - block_type_trees[x] = new HuffmanCode(0, 0); - block_len_trees[x] = new HuffmanCode(0, 0); - } - - while (!input_end) { - var meta_block_remaining_len = 0; - var is_uncompressed; - var block_length = [ 1 << 28, 1 << 28, 1 << 28 ]; - var block_type = [ 0 ]; - var num_block_types = [ 1, 1, 1 ]; - var block_type_rb = [ 0, 1, 0, 1, 0, 1 ]; - var block_type_rb_index = [ 0 ]; - var distance_postfix_bits; - var num_direct_distance_codes; - var distance_postfix_mask; - var num_distance_codes; - var context_map = null; - var context_modes = null; - var num_literal_htrees; - var dist_context_map = null; - var num_dist_htrees; - var context_offset = 0; - var context_map_slice = null; - var literal_htree_index = 0; - var dist_context_offset = 0; - var dist_context_map_slice = null; - var dist_htree_index = 0; - var context_lookup_offset1 = 0; - var context_lookup_offset2 = 0; - var context_mode; - var htree_command; - - for (i = 0; i < 3; ++i) { - hgroup[i].codes = null; - hgroup[i].htrees = null; - } - - br.readMoreInput(); - - var _out = DecodeMetaBlockLength(br); - meta_block_remaining_len = _out.meta_block_length; - if (pos + meta_block_remaining_len > output.buffer.length) { - /* We need to grow the output buffer to fit the additional data. */ - var tmp = new Uint8Array( pos + meta_block_remaining_len ); - tmp.set( output.buffer ); - output.buffer = tmp; - } - input_end = _out.input_end; - is_uncompressed = _out.is_uncompressed; - - if (_out.is_metadata) { - JumpToByteBoundary(br); - - for (; meta_block_remaining_len > 0; --meta_block_remaining_len) { - br.readMoreInput(); - /* Read one byte and ignore it. */ - br.readBits(8); - } - - continue; - } - - if (meta_block_remaining_len === 0) { - continue; - } - - if (is_uncompressed) { - br.bit_pos_ = (br.bit_pos_ + 7) & ~7; - CopyUncompressedBlockToOutput(output, meta_block_remaining_len, pos, - ringbuffer, ringbuffer_mask, br); - pos += meta_block_remaining_len; - continue; - } - - for (i = 0; i < 3; ++i) { - num_block_types[i] = DecodeVarLenUint8(br) + 1; - if (num_block_types[i] >= 2) { - ReadHuffmanCode(num_block_types[i] + 2, block_type_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); - ReadHuffmanCode(kNumBlockLengthCodes, block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); - block_length[i] = ReadBlockLength(block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); - block_type_rb_index[i] = 1; - } - } - - br.readMoreInput(); - - distance_postfix_bits = br.readBits(2); - num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES + (br.readBits(4) << distance_postfix_bits); - distance_postfix_mask = (1 << distance_postfix_bits) - 1; - num_distance_codes = (num_direct_distance_codes + (48 << distance_postfix_bits)); - context_modes = new Uint8Array(num_block_types[0]); - - for (i = 0; i < num_block_types[0]; ++i) { - br.readMoreInput(); - context_modes[i] = (br.readBits(2) << 1); - } - - var _o1 = DecodeContextMap(num_block_types[0] << kLiteralContextBits, br); - num_literal_htrees = _o1.num_htrees; - context_map = _o1.context_map; - - var _o2 = DecodeContextMap(num_block_types[2] << kDistanceContextBits, br); - num_dist_htrees = _o2.num_htrees; - dist_context_map = _o2.context_map; - - hgroup[0] = new HuffmanTreeGroup(kNumLiteralCodes, num_literal_htrees); - hgroup[1] = new HuffmanTreeGroup(kNumInsertAndCopyCodes, num_block_types[1]); - hgroup[2] = new HuffmanTreeGroup(num_distance_codes, num_dist_htrees); - - for (i = 0; i < 3; ++i) { - hgroup[i].decode(br); - } - - context_map_slice = 0; - dist_context_map_slice = 0; - context_mode = context_modes[block_type[0]]; - context_lookup_offset1 = Context.lookupOffsets[context_mode]; - context_lookup_offset2 = Context.lookupOffsets[context_mode + 1]; - htree_command = hgroup[1].htrees[0]; - - while (meta_block_remaining_len > 0) { - var cmd_code; - var range_idx; - var insert_code; - var copy_code; - var insert_length; - var copy_length; - var distance_code; - var distance; - var context; - var j; - var copy_dst; - - br.readMoreInput(); - - if (block_length[1] === 0) { - DecodeBlockType(num_block_types[1], - block_type_trees, 1, block_type, block_type_rb, - block_type_rb_index, br); - block_length[1] = ReadBlockLength(block_len_trees, HUFFMAN_MAX_TABLE_SIZE, br); - htree_command = hgroup[1].htrees[block_type[1]]; - } - --block_length[1]; - cmd_code = ReadSymbol(hgroup[1].codes, htree_command, br); - range_idx = cmd_code >> 6; - if (range_idx >= 2) { - range_idx -= 2; - distance_code = -1; - } else { - distance_code = 0; - } - insert_code = Prefix.kInsertRangeLut[range_idx] + ((cmd_code >> 3) & 7); - copy_code = Prefix.kCopyRangeLut[range_idx] + (cmd_code & 7); - insert_length = Prefix.kInsertLengthPrefixCode[insert_code].offset + - br.readBits(Prefix.kInsertLengthPrefixCode[insert_code].nbits); - copy_length = Prefix.kCopyLengthPrefixCode[copy_code].offset + - br.readBits(Prefix.kCopyLengthPrefixCode[copy_code].nbits); - prev_byte1 = ringbuffer[pos-1 & ringbuffer_mask]; - prev_byte2 = ringbuffer[pos-2 & ringbuffer_mask]; - for (j = 0; j < insert_length; ++j) { - br.readMoreInput(); - - if (block_length[0] === 0) { - DecodeBlockType(num_block_types[0], - block_type_trees, 0, block_type, block_type_rb, - block_type_rb_index, br); - block_length[0] = ReadBlockLength(block_len_trees, 0, br); - context_offset = block_type[0] << kLiteralContextBits; - context_map_slice = context_offset; - context_mode = context_modes[block_type[0]]; - context_lookup_offset1 = Context.lookupOffsets[context_mode]; - context_lookup_offset2 = Context.lookupOffsets[context_mode + 1]; - } - context = (Context.lookup[context_lookup_offset1 + prev_byte1] | - Context.lookup[context_lookup_offset2 + prev_byte2]); - literal_htree_index = context_map[context_map_slice + context]; - --block_length[0]; - prev_byte2 = prev_byte1; - prev_byte1 = ReadSymbol(hgroup[0].codes, hgroup[0].htrees[literal_htree_index], br); - ringbuffer[pos & ringbuffer_mask] = prev_byte1; - if ((pos & ringbuffer_mask) === ringbuffer_mask) { - output.write(ringbuffer, ringbuffer_size); - } - ++pos; - } - meta_block_remaining_len -= insert_length; - if (meta_block_remaining_len <= 0) break; - - if (distance_code < 0) { - var context; - - br.readMoreInput(); - if (block_length[2] === 0) { - DecodeBlockType(num_block_types[2], - block_type_trees, 2, block_type, block_type_rb, - block_type_rb_index, br); - block_length[2] = ReadBlockLength(block_len_trees, 2 * HUFFMAN_MAX_TABLE_SIZE, br); - dist_context_offset = block_type[2] << kDistanceContextBits; - dist_context_map_slice = dist_context_offset; - } - --block_length[2]; - context = (copy_length > 4 ? 3 : copy_length - 2) & 0xff; - dist_htree_index = dist_context_map[dist_context_map_slice + context]; - distance_code = ReadSymbol(hgroup[2].codes, hgroup[2].htrees[dist_htree_index], br); - if (distance_code >= num_direct_distance_codes) { - var nbits; - var postfix; - var offset; - distance_code -= num_direct_distance_codes; - postfix = distance_code & distance_postfix_mask; - distance_code >>= distance_postfix_bits; - nbits = (distance_code >> 1) + 1; - offset = ((2 + (distance_code & 1)) << nbits) - 4; - distance_code = num_direct_distance_codes + - ((offset + br.readBits(nbits)) << - distance_postfix_bits) + postfix; - } - } - - /* Convert the distance code to the actual distance by possibly looking */ - /* up past distnaces from the ringbuffer. */ - distance = TranslateShortCodes(distance_code, dist_rb, dist_rb_idx); - if (distance < 0) { - throw new Error('[BrotliDecompress] invalid distance'); - } - - if (pos < max_backward_distance && - max_distance !== max_backward_distance) { - max_distance = pos; - } else { - max_distance = max_backward_distance; - } - - copy_dst = pos & ringbuffer_mask; - - if (distance > max_distance) { - if (copy_length >= BrotliDictionary.minDictionaryWordLength && - copy_length <= BrotliDictionary.maxDictionaryWordLength) { - var offset = BrotliDictionary.offsetsByLength[copy_length]; - var word_id = distance - max_distance - 1; - var shift = BrotliDictionary.sizeBitsByLength[copy_length]; - var mask = (1 << shift) - 1; - var word_idx = word_id & mask; - var transform_idx = word_id >> shift; - offset += word_idx * copy_length; - if (transform_idx < Transform.kNumTransforms) { - var len = Transform.transformDictionaryWord(ringbuffer, copy_dst, offset, copy_length, transform_idx); - copy_dst += len; - pos += len; - meta_block_remaining_len -= len; - if (copy_dst >= ringbuffer_end) { - output.write(ringbuffer, ringbuffer_size); - - for (var _x = 0; _x < (copy_dst - ringbuffer_end); _x++) - ringbuffer[_x] = ringbuffer[ringbuffer_end + _x]; - } - } else { - throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + - " len: " + copy_length + " bytes left: " + meta_block_remaining_len); - } - } else { - throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + - " len: " + copy_length + " bytes left: " + meta_block_remaining_len); - } - } else { - if (distance_code > 0) { - dist_rb[dist_rb_idx & 3] = distance; - ++dist_rb_idx; - } - - if (copy_length > meta_block_remaining_len) { - throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + - " len: " + copy_length + " bytes left: " + meta_block_remaining_len); - } - - for (j = 0; j < copy_length; ++j) { - ringbuffer[pos & ringbuffer_mask] = ringbuffer[(pos - distance) & ringbuffer_mask]; - if ((pos & ringbuffer_mask) === ringbuffer_mask) { - output.write(ringbuffer, ringbuffer_size); - } - ++pos; - --meta_block_remaining_len; - } - } - - /* When we get here, we must have inserted at least one literal and */ - /* made a copy of at least length two, therefore accessing the last 2 */ - /* bytes is valid. */ - prev_byte1 = ringbuffer[(pos - 1) & ringbuffer_mask]; - prev_byte2 = ringbuffer[(pos - 2) & ringbuffer_mask]; - } - - /* Protect pos from overflow, wrap it around at every GB of input data */ - pos &= 0x3fffffff; - } - - output.write(ringbuffer, pos & ringbuffer_mask); -} - -exports.BrotliDecompress = BrotliDecompress; - -BrotliDictionary.init(); - -},{"./bit_reader":1,"./context":2,"./dictionary":6,"./huffman":7,"./prefix":9,"./streams":10,"./transform":11}],4:[function(require,module,exports){ -var base64 = require('base64-js'); -//var fs = require('fs'); - -/** - * The normal dictionary-data.js is quite large, which makes it - * unsuitable for browser usage. In order to make it smaller, - * we read dictionary.bin, which is a compressed version of - * the dictionary, and on initial load, Brotli decompresses - * it's own dictionary. 😜 - */ -exports.init = function() { - var BrotliDecompressBuffer = require('./decode').BrotliDecompressBuffer; - var compressed = base64.toByteArray(require('./dictionary.bin.js')); - return BrotliDecompressBuffer(compressed); -}; - -},{"./decode":3,"./dictionary.bin.js":5,"base64-js":8}],5:[function(require,module,exports){ -module.exports="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"; - -},{}],6:[function(require,module,exports){ -/* Copyright 2013 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Collection of static dictionary words. -*/ - -var data = require('./dictionary-browser'); -exports.init = function() { - exports.dictionary = data.init(); -}; - -exports.offsetsByLength = new Uint32Array([ - 0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, - 53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536, - 115968, 118528, 119872, 121280, 122016, -]); - -exports.sizeBitsByLength = new Uint8Array([ - 0, 0, 0, 0, 10, 10, 11, 11, 10, 10, - 10, 10, 10, 9, 9, 8, 7, 7, 8, 7, - 7, 6, 6, 5, 5, -]); - -exports.minDictionaryWordLength = 4; -exports.maxDictionaryWordLength = 24; - -},{"./dictionary-browser":4}],7:[function(require,module,exports){ -function HuffmanCode(bits, value) { - this.bits = bits; /* number of bits used for this symbol */ - this.value = value; /* symbol value or table offset */ -} - -exports.HuffmanCode = HuffmanCode; - -var MAX_LENGTH = 15; - -/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the - bit-wise reversal of the len least significant bits of key. */ -function GetNextKey(key, len) { - var step = 1 << (len - 1); - while (key & step) { - step >>= 1; - } - return (key & (step - 1)) + step; -} - -/* Stores code in table[0], table[step], table[2*step], ..., table[end] */ -/* Assumes that end is an integer multiple of step */ -function ReplicateValue(table, i, step, end, code) { - do { - end -= step; - table[i + end] = new HuffmanCode(code.bits, code.value); - } while (end > 0); -} - -/* Returns the table width of the next 2nd level table. count is the histogram - of bit lengths for the remaining symbols, len is the code length of the next - processed symbol */ -function NextTableBitSize(count, len, root_bits) { - var left = 1 << (len - root_bits); - while (len < MAX_LENGTH) { - left -= count[len]; - if (left <= 0) break; - ++len; - left <<= 1; - } - return len - root_bits; -} - -exports.BrotliBuildHuffmanTable = function(root_table, table, root_bits, code_lengths, code_lengths_size) { - var start_table = table; - var code; /* current table entry */ - var len; /* current code length */ - var symbol; /* symbol index in original or sorted table */ - var key; /* reversed prefix code */ - var step; /* step size to replicate values in current table */ - var low; /* low bits for current root entry */ - var mask; /* mask for low bits */ - var table_bits; /* key length of current table */ - var table_size; /* size of current table */ - var total_size; /* sum of root table size and 2nd level table sizes */ - var sorted; /* symbols sorted by code length */ - var count = new Int32Array(MAX_LENGTH + 1); /* number of codes of each length */ - var offset = new Int32Array(MAX_LENGTH + 1); /* offsets in sorted table for each length */ - - sorted = new Int32Array(code_lengths_size); - - /* build histogram of code lengths */ - for (symbol = 0; symbol < code_lengths_size; symbol++) { - count[code_lengths[symbol]]++; - } - - /* generate offsets into sorted symbol table by code length */ - offset[1] = 0; - for (len = 1; len < MAX_LENGTH; len++) { - offset[len + 1] = offset[len] + count[len]; - } - - /* sort symbols by length, by symbol order within each length */ - for (symbol = 0; symbol < code_lengths_size; symbol++) { - if (code_lengths[symbol] !== 0) { - sorted[offset[code_lengths[symbol]]++] = symbol; - } - } - - table_bits = root_bits; - table_size = 1 << table_bits; - total_size = table_size; - - /* special case code with only one value */ - if (offset[MAX_LENGTH] === 1) { - for (key = 0; key < total_size; ++key) { - root_table[table + key] = new HuffmanCode(0, sorted[0] & 0xffff); - } - - return total_size; - } - - /* fill in root table */ - key = 0; - symbol = 0; - for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) { - for (; count[len] > 0; --count[len]) { - code = new HuffmanCode(len & 0xff, sorted[symbol++] & 0xffff); - ReplicateValue(root_table, table + key, step, table_size, code); - key = GetNextKey(key, len); - } - } - - /* fill in 2nd level tables and add pointers to root table */ - mask = total_size - 1; - low = -1; - for (len = root_bits + 1, step = 2; len <= MAX_LENGTH; ++len, step <<= 1) { - for (; count[len] > 0; --count[len]) { - if ((key & mask) !== low) { - table += table_size; - table_bits = NextTableBitSize(count, len, root_bits); - table_size = 1 << table_bits; - total_size += table_size; - low = key & mask; - root_table[start_table + low] = new HuffmanCode((table_bits + root_bits) & 0xff, ((table - start_table) - low) & 0xffff); - } - code = new HuffmanCode((len - root_bits) & 0xff, sorted[symbol++] & 0xffff); - ReplicateValue(root_table, table + (key >> root_bits), step, table_size, code); - key = GetNextKey(key, len); - } - } - - return total_size; -} - -},{}],8:[function(require,module,exports){ -'use strict' - -exports.byteLength = byteLength -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray - -var lookup = [] -var revLookup = [] -var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array - -var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i -} - -// Support decoding URL-safe base64 strings, as Node.js does. -// See: https://en.wikipedia.org/wiki/Base64#URL_applications -revLookup['-'.charCodeAt(0)] = 62 -revLookup['_'.charCodeAt(0)] = 63 - -function getLens (b64) { - var len = b64.length - - if (len % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // Trim off extra bytes after placeholder bytes are found - // See: https://github.com/beatgammit/base64-js/issues/42 - var validLen = b64.indexOf('=') - if (validLen === -1) validLen = len - - var placeHoldersLen = validLen === len - ? 0 - : 4 - (validLen % 4) - - return [validLen, placeHoldersLen] -} - -// base64 is 4/3 + up to two characters of the original data -function byteLength (b64) { - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] - return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen -} - -function _byteLength (b64, validLen, placeHoldersLen) { - return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen -} - -function toByteArray (b64) { - var tmp - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] - - var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) - - var curByte = 0 - - // if there are placeholders, only get up to the last complete 4 chars - var len = placeHoldersLen > 0 - ? validLen - 4 - : validLen - - for (var i = 0; i < len; i += 4) { - tmp = - (revLookup[b64.charCodeAt(i)] << 18) | - (revLookup[b64.charCodeAt(i + 1)] << 12) | - (revLookup[b64.charCodeAt(i + 2)] << 6) | - revLookup[b64.charCodeAt(i + 3)] - arr[curByte++] = (tmp >> 16) & 0xFF - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF - } - - if (placeHoldersLen === 2) { - tmp = - (revLookup[b64.charCodeAt(i)] << 2) | - (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[curByte++] = tmp & 0xFF - } - - if (placeHoldersLen === 1) { - tmp = - (revLookup[b64.charCodeAt(i)] << 10) | - (revLookup[b64.charCodeAt(i + 1)] << 4) | - (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF - } - - return arr -} - -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + - lookup[num >> 12 & 0x3F] + - lookup[num >> 6 & 0x3F] + - lookup[num & 0x3F] -} - -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = - ((uint8[i] << 16) & 0xFF0000) + - ((uint8[i + 1] << 8) & 0xFF00) + - (uint8[i + 2] & 0xFF) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} - -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk( - uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) - )) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - parts.push( - lookup[tmp >> 2] + - lookup[(tmp << 4) & 0x3F] + - '==' - ) - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + uint8[len - 1] - parts.push( - lookup[tmp >> 10] + - lookup[(tmp >> 4) & 0x3F] + - lookup[(tmp << 2) & 0x3F] + - '=' - ) - } - - return parts.join('') -} - -},{}],9:[function(require,module,exports){ -/* Copyright 2013 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Lookup tables to map prefix codes to value ranges. This is used during - decoding of the block lengths, literal insertion lengths and copy lengths. -*/ - -/* Represents the range of values belonging to a prefix code: */ -/* [offset, offset + 2^nbits) */ -function PrefixCodeRange(offset, nbits) { - this.offset = offset; - this.nbits = nbits; -} - -exports.kBlockLengthPrefixCode = [ - new PrefixCodeRange(1, 2), new PrefixCodeRange(5, 2), new PrefixCodeRange(9, 2), new PrefixCodeRange(13, 2), - new PrefixCodeRange(17, 3), new PrefixCodeRange(25, 3), new PrefixCodeRange(33, 3), new PrefixCodeRange(41, 3), - new PrefixCodeRange(49, 4), new PrefixCodeRange(65, 4), new PrefixCodeRange(81, 4), new PrefixCodeRange(97, 4), - new PrefixCodeRange(113, 5), new PrefixCodeRange(145, 5), new PrefixCodeRange(177, 5), new PrefixCodeRange(209, 5), - new PrefixCodeRange(241, 6), new PrefixCodeRange(305, 6), new PrefixCodeRange(369, 7), new PrefixCodeRange(497, 8), - new PrefixCodeRange(753, 9), new PrefixCodeRange(1265, 10), new PrefixCodeRange(2289, 11), new PrefixCodeRange(4337, 12), - new PrefixCodeRange(8433, 13), new PrefixCodeRange(16625, 24) -]; - -exports.kInsertLengthPrefixCode = [ - new PrefixCodeRange(0, 0), new PrefixCodeRange(1, 0), new PrefixCodeRange(2, 0), new PrefixCodeRange(3, 0), - new PrefixCodeRange(4, 0), new PrefixCodeRange(5, 0), new PrefixCodeRange(6, 1), new PrefixCodeRange(8, 1), - new PrefixCodeRange(10, 2), new PrefixCodeRange(14, 2), new PrefixCodeRange(18, 3), new PrefixCodeRange(26, 3), - new PrefixCodeRange(34, 4), new PrefixCodeRange(50, 4), new PrefixCodeRange(66, 5), new PrefixCodeRange(98, 5), - new PrefixCodeRange(130, 6), new PrefixCodeRange(194, 7), new PrefixCodeRange(322, 8), new PrefixCodeRange(578, 9), - new PrefixCodeRange(1090, 10), new PrefixCodeRange(2114, 12), new PrefixCodeRange(6210, 14), new PrefixCodeRange(22594, 24), -]; - -exports.kCopyLengthPrefixCode = [ - new PrefixCodeRange(2, 0), new PrefixCodeRange(3, 0), new PrefixCodeRange(4, 0), new PrefixCodeRange(5, 0), - new PrefixCodeRange(6, 0), new PrefixCodeRange(7, 0), new PrefixCodeRange(8, 0), new PrefixCodeRange(9, 0), - new PrefixCodeRange(10, 1), new PrefixCodeRange(12, 1), new PrefixCodeRange(14, 2), new PrefixCodeRange(18, 2), - new PrefixCodeRange(22, 3), new PrefixCodeRange(30, 3), new PrefixCodeRange(38, 4), new PrefixCodeRange(54, 4), - new PrefixCodeRange(70, 5), new PrefixCodeRange(102, 5), new PrefixCodeRange(134, 6), new PrefixCodeRange(198, 7), - new PrefixCodeRange(326, 8), new PrefixCodeRange(582, 9), new PrefixCodeRange(1094, 10), new PrefixCodeRange(2118, 24), -]; - -exports.kInsertRangeLut = [ - 0, 0, 8, 8, 0, 16, 8, 16, 16, -]; - -exports.kCopyRangeLut = [ - 0, 8, 0, 8, 16, 0, 16, 8, 16, -]; - -},{}],10:[function(require,module,exports){ -function BrotliInput(buffer) { - this.buffer = buffer; - this.pos = 0; -} - -BrotliInput.prototype.read = function(buf, i, count) { - if (this.pos + count > this.buffer.length) { - count = this.buffer.length - this.pos; - } - - for (var p = 0; p < count; p++) - buf[i + p] = this.buffer[this.pos + p]; - - this.pos += count; - return count; -} - -exports.BrotliInput = BrotliInput; - -function BrotliOutput(buf) { - this.buffer = buf; - this.pos = 0; -} - -BrotliOutput.prototype.write = function(buf, count) { - if (this.pos + count > this.buffer.length) - throw new Error('Output buffer is not large enough'); - - this.buffer.set(buf.subarray(0, count), this.pos); - this.pos += count; - return count; -}; - -exports.BrotliOutput = BrotliOutput; - -},{}],11:[function(require,module,exports){ -/* Copyright 2013 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Transformations on dictionary words. -*/ - -var BrotliDictionary = require('./dictionary'); - -var kIdentity = 0; -var kOmitLast1 = 1; -var kOmitLast2 = 2; -var kOmitLast3 = 3; -var kOmitLast4 = 4; -var kOmitLast5 = 5; -var kOmitLast6 = 6; -var kOmitLast7 = 7; -var kOmitLast8 = 8; -var kOmitLast9 = 9; -var kUppercaseFirst = 10; -var kUppercaseAll = 11; -var kOmitFirst1 = 12; -var kOmitFirst2 = 13; -var kOmitFirst3 = 14; -var kOmitFirst4 = 15; -var kOmitFirst5 = 16; -var kOmitFirst6 = 17; -var kOmitFirst7 = 18; -var kOmitFirst8 = 19; -var kOmitFirst9 = 20; - -function Transform(prefix, transform, suffix) { - this.prefix = new Uint8Array(prefix.length); - this.transform = transform; - this.suffix = new Uint8Array(suffix.length); - - for (var i = 0; i < prefix.length; i++) - this.prefix[i] = prefix.charCodeAt(i); - - for (var i = 0; i < suffix.length; i++) - this.suffix[i] = suffix.charCodeAt(i); -} - -var kTransforms = [ - new Transform( "", kIdentity, "" ), - new Transform( "", kIdentity, " " ), - new Transform( " ", kIdentity, " " ), - new Transform( "", kOmitFirst1, "" ), - new Transform( "", kUppercaseFirst, " " ), - new Transform( "", kIdentity, " the " ), - new Transform( " ", kIdentity, "" ), - new Transform( "s ", kIdentity, " " ), - new Transform( "", kIdentity, " of " ), - new Transform( "", kUppercaseFirst, "" ), - new Transform( "", kIdentity, " and " ), - new Transform( "", kOmitFirst2, "" ), - new Transform( "", kOmitLast1, "" ), - new Transform( ", ", kIdentity, " " ), - new Transform( "", kIdentity, ", " ), - new Transform( " ", kUppercaseFirst, " " ), - new Transform( "", kIdentity, " in " ), - new Transform( "", kIdentity, " to " ), - new Transform( "e ", kIdentity, " " ), - new Transform( "", kIdentity, "\"" ), - new Transform( "", kIdentity, "." ), - new Transform( "", kIdentity, "\">" ), - new Transform( "", kIdentity, "\n" ), - new Transform( "", kOmitLast3, "" ), - new Transform( "", kIdentity, "]" ), - new Transform( "", kIdentity, " for " ), - new Transform( "", kOmitFirst3, "" ), - new Transform( "", kOmitLast2, "" ), - new Transform( "", kIdentity, " a " ), - new Transform( "", kIdentity, " that " ), - new Transform( " ", kUppercaseFirst, "" ), - new Transform( "", kIdentity, ". " ), - new Transform( ".", kIdentity, "" ), - new Transform( " ", kIdentity, ", " ), - new Transform( "", kOmitFirst4, "" ), - new Transform( "", kIdentity, " with " ), - new Transform( "", kIdentity, "'" ), - new Transform( "", kIdentity, " from " ), - new Transform( "", kIdentity, " by " ), - new Transform( "", kOmitFirst5, "" ), - new Transform( "", kOmitFirst6, "" ), - new Transform( " the ", kIdentity, "" ), - new Transform( "", kOmitLast4, "" ), - new Transform( "", kIdentity, ". The " ), - new Transform( "", kUppercaseAll, "" ), - new Transform( "", kIdentity, " on " ), - new Transform( "", kIdentity, " as " ), - new Transform( "", kIdentity, " is " ), - new Transform( "", kOmitLast7, "" ), - new Transform( "", kOmitLast1, "ing " ), - new Transform( "", kIdentity, "\n\t" ), - new Transform( "", kIdentity, ":" ), - new Transform( " ", kIdentity, ". " ), - new Transform( "", kIdentity, "ed " ), - new Transform( "", kOmitFirst9, "" ), - new Transform( "", kOmitFirst7, "" ), - new Transform( "", kOmitLast6, "" ), - new Transform( "", kIdentity, "(" ), - new Transform( "", kUppercaseFirst, ", " ), - new Transform( "", kOmitLast8, "" ), - new Transform( "", kIdentity, " at " ), - new Transform( "", kIdentity, "ly " ), - new Transform( " the ", kIdentity, " of " ), - new Transform( "", kOmitLast5, "" ), - new Transform( "", kOmitLast9, "" ), - new Transform( " ", kUppercaseFirst, ", " ), - new Transform( "", kUppercaseFirst, "\"" ), - new Transform( ".", kIdentity, "(" ), - new Transform( "", kUppercaseAll, " " ), - new Transform( "", kUppercaseFirst, "\">" ), - new Transform( "", kIdentity, "=\"" ), - new Transform( " ", kIdentity, "." ), - new Transform( ".com/", kIdentity, "" ), - new Transform( " the ", kIdentity, " of the " ), - new Transform( "", kUppercaseFirst, "'" ), - new Transform( "", kIdentity, ". This " ), - new Transform( "", kIdentity, "," ), - new Transform( ".", kIdentity, " " ), - new Transform( "", kUppercaseFirst, "(" ), - new Transform( "", kUppercaseFirst, "." ), - new Transform( "", kIdentity, " not " ), - new Transform( " ", kIdentity, "=\"" ), - new Transform( "", kIdentity, "er " ), - new Transform( " ", kUppercaseAll, " " ), - new Transform( "", kIdentity, "al " ), - new Transform( " ", kUppercaseAll, "" ), - new Transform( "", kIdentity, "='" ), - new Transform( "", kUppercaseAll, "\"" ), - new Transform( "", kUppercaseFirst, ". " ), - new Transform( " ", kIdentity, "(" ), - new Transform( "", kIdentity, "ful " ), - new Transform( " ", kUppercaseFirst, ". " ), - new Transform( "", kIdentity, "ive " ), - new Transform( "", kIdentity, "less " ), - new Transform( "", kUppercaseAll, "'" ), - new Transform( "", kIdentity, "est " ), - new Transform( " ", kUppercaseFirst, "." ), - new Transform( "", kUppercaseAll, "\">" ), - new Transform( " ", kIdentity, "='" ), - new Transform( "", kUppercaseFirst, "," ), - new Transform( "", kIdentity, "ize " ), - new Transform( "", kUppercaseAll, "." ), - new Transform( "\xc2\xa0", kIdentity, "" ), - new Transform( " ", kIdentity, "," ), - new Transform( "", kUppercaseFirst, "=\"" ), - new Transform( "", kUppercaseAll, "=\"" ), - new Transform( "", kIdentity, "ous " ), - new Transform( "", kUppercaseAll, ", " ), - new Transform( "", kUppercaseFirst, "='" ), - new Transform( " ", kUppercaseFirst, "," ), - new Transform( " ", kUppercaseAll, "=\"" ), - new Transform( " ", kUppercaseAll, ", " ), - new Transform( "", kUppercaseAll, "," ), - new Transform( "", kUppercaseAll, "(" ), - new Transform( "", kUppercaseAll, ". " ), - new Transform( " ", kUppercaseAll, "." ), - new Transform( "", kUppercaseAll, "='" ), - new Transform( " ", kUppercaseAll, ". " ), - new Transform( " ", kUppercaseFirst, "=\"" ), - new Transform( " ", kUppercaseAll, "='" ), - new Transform( " ", kUppercaseFirst, "='" ) -]; - -exports.kTransforms = kTransforms; -exports.kNumTransforms = kTransforms.length; - -function ToUpperCase(p, i) { - if (p[i] < 0xc0) { - if (p[i] >= 97 && p[i] <= 122) { - p[i] ^= 32; - } - return 1; - } - - /* An overly simplified uppercasing model for utf-8. */ - if (p[i] < 0xe0) { - p[i + 1] ^= 32; - return 2; - } - - /* An arbitrary transform for three byte characters. */ - p[i + 2] ^= 5; - return 3; -} - -exports.transformDictionaryWord = function(dst, idx, word, len, transform) { - var prefix = kTransforms[transform].prefix; - var suffix = kTransforms[transform].suffix; - var t = kTransforms[transform].transform; - var skip = t < kOmitFirst1 ? 0 : t - (kOmitFirst1 - 1); - var i = 0; - var start_idx = idx; - var uppercase; - - if (skip > len) { - skip = len; - } - - var prefix_pos = 0; - while (prefix_pos < prefix.length) { - dst[idx++] = prefix[prefix_pos++]; - } - - word += skip; - len -= skip; - - if (t <= kOmitLast9) { - len -= t; - } - - for (i = 0; i < len; i++) { - dst[idx++] = BrotliDictionary.dictionary[word + i]; - } - - uppercase = idx - len; - - if (t === kUppercaseFirst) { - ToUpperCase(dst, uppercase); - } else if (t === kUppercaseAll) { - while (len > 0) { - var step = ToUpperCase(dst, uppercase); - uppercase += step; - len -= step; - } - } - - var suffix_pos = 0; - while (suffix_pos < suffix.length) { - dst[idx++] = suffix[suffix_pos++]; - } - - return idx - start_idx; -} - -},{"./dictionary":6}],12:[function(require,module,exports){ -module.exports = require('./dec/decode').BrotliDecompressBuffer; - -},{"./dec/decode":3}]},{},[12])(12) -}); -/* eslint-enable */ diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index ffa6c0c1ac77e5..4deec2173ee46a 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -59,6 +59,7 @@ "@wordpress/escape-html": "file:../escape-html", "@wordpress/fields": "file:../fields", "@wordpress/global-styles-engine": "file:../global-styles-engine", + "@wordpress/global-styles-ui": "file:../global-styles-ui", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", diff --git a/packages/edit-site/src/components/canvas-loader/index.js b/packages/edit-site/src/components/canvas-loader/index.js index 95dd8f24612938..6727497acf044e 100644 --- a/packages/edit-site/src/components/canvas-loader/index.js +++ b/packages/edit-site/src/components/canvas-loader/index.js @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { privateApis as componentsPrivateApis, ProgressBar, @@ -13,17 +12,13 @@ import { useSelect } from '@wordpress/data'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; -import { useStylesPreviewColors } from '../global-styles/hooks'; +import { useStyle } from '../global-styles/hooks'; const { Theme } = unlock( componentsPrivateApis ); -const { useGlobalStyle } = unlock( blockEditorPrivateApis ); export default function CanvasLoader( { id } ) { - const [ fallbackIndicatorColor ] = useGlobalStyle( 'color.text' ); - const [ backgroundColor ] = useGlobalStyle( 'color.background' ); - const { highlightedColors } = useStylesPreviewColors(); - const indicatorColor = - highlightedColors[ 0 ]?.color ?? fallbackIndicatorColor; + const textColor = useStyle( 'color.text' ); + const backgroundColor = useStyle( 'color.background' ); const { elapsed, total } = useSelect( ( select ) => { const selectorsByStatus = select( coreStore ).countSelectorsByStatus(); const resolving = selectorsByStatus.resolving ?? 0; @@ -36,7 +31,7 @@ export default function CanvasLoader( { id } ) { return (
- +
diff --git a/packages/edit-site/src/components/global-styles-sidebar/index.js b/packages/edit-site/src/components/global-styles-sidebar/index.js index 02a29dac5c0b7d..ccdff5ae387c65 100644 --- a/packages/edit-site/src/components/global-styles-sidebar/index.js +++ b/packages/edit-site/src/components/global-styles-sidebar/index.js @@ -5,21 +5,21 @@ import { FlexItem, Flex, Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { styles, seen, backup } from '@wordpress/icons'; import { useSelect, useDispatch } from '@wordpress/data'; -import { useEffect, useRef } from '@wordpress/element'; +import { useEffect, useRef, useState } from '@wordpress/element'; import { store as preferencesStore } from '@wordpress/preferences'; import { store as editorStore, privateApis as editorPrivateApis, } from '@wordpress/editor'; -import { useViewportMatch } from '@wordpress/compose'; +import { useViewportMatch, usePrevious } from '@wordpress/compose'; import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ -import { GlobalStylesUI } from '../global-styles'; +import GlobalStylesUI from '../global-styles'; +import { GlobalStylesActionMenu } from '../global-styles/menu'; import { store as editSiteStore } from '../../store'; -import { GlobalStylesMenuSlot } from '../global-styles/ui'; import { unlock } from '../../lock-unlock'; import { store as coreStore } from '@wordpress/core-data'; import DefaultSidebar from './default-sidebar'; @@ -37,6 +37,7 @@ export default function GlobalStylesSidebar() { hasRevisions, isRevisionsOpened, isRevisionsStyleBookOpened, + activeComplementaryArea, } = useSelect( ( select ) => { const { getActiveComplementaryArea } = select( interfaceStore ); @@ -75,6 +76,10 @@ export default function GlobalStylesSidebar() { canvasContainerView, isRevisionsOpened: 'global-styles-revisions' === canvasContainerView, + activeComplementaryArea: + select( interfaceStore ).getActiveComplementaryArea( + 'core' + ), }; }, [ canvas ] @@ -83,6 +88,18 @@ export default function GlobalStylesSidebar() { useDispatch( editSiteStore ) ); const isMobileViewport = useViewportMatch( 'medium', '<' ); + const [ globalStylesPath, setGlobalStylesPath ] = useState( '/' ); + const previousActiveArea = usePrevious( activeComplementaryArea ); + + // Reset path when sidebar opens + useEffect( () => { + if ( + activeComplementaryArea === 'edit-site/global-styles' && + previousActiveArea !== 'edit-site/global-styles' + ) { + setGlobalStylesPath( '/' ); + } + }, [ activeComplementaryArea, previousActiveArea, setGlobalStylesPath ] ); useEffect( () => { if ( shouldClearCanvasContainerView ) { @@ -195,12 +212,15 @@ export default function GlobalStylesSidebar() { size="compact" /> - + } > - + ); } diff --git a/packages/edit-site/src/components/global-styles-sidebar/style.scss b/packages/edit-site/src/components/global-styles-sidebar/style.scss index 766bd97dc860f7..6b9e318fd6b7e3 100644 --- a/packages/edit-site/src/components/global-styles-sidebar/style.scss +++ b/packages/edit-site/src/components/global-styles-sidebar/style.scss @@ -9,6 +9,10 @@ &__panel { flex: 1; } + + .components-navigator-screen { + padding: 0; + } } .edit-site-global-styles-sidebar .edit-site-global-styles-sidebar__header-title { @@ -49,8 +53,8 @@ padding: 0 $grid-unit-20; } -.edit-site-global-styles-color-palette-panel, -.edit-site-global-styles-gradient-palette-panel { +.global-styles-ui-color-palette-panel, +.global-styles-ui-gradient-palette-panel { padding: $grid-unit-20; } diff --git a/packages/edit-site/src/components/global-styles/block-link.js b/packages/edit-site/src/components/global-styles/block-link.js new file mode 100644 index 00000000000000..2fcdf3b765980c --- /dev/null +++ b/packages/edit-site/src/components/global-styles/block-link.js @@ -0,0 +1,65 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { usePrevious } from '@wordpress/compose'; + +/** + * Auto-navigate to block styles when a block is selected in the canvas. + * + * @param {Object} props + * @param {string} props.path Current navigation path. + * @param {Function} props.onPathChange Callback to change the navigation path. + */ +export function GlobalStylesBlockLink( { path, onPathChange } ) { + const { selectedBlockName, selectedBlockClientId } = useSelect( + ( select ) => { + const { getSelectedBlockClientId, getBlockName } = + select( blockEditorStore ); + const clientId = getSelectedBlockClientId(); + return { + selectedBlockName: getBlockName( clientId ), + selectedBlockClientId: clientId, + }; + }, + [] + ); + + // const blockHasGlobalStyles = useBlockHasGlobalStyles( selectedBlockName ); + const blockHasGlobalStyles = true; + const previousBlockClientId = usePrevious( selectedBlockClientId ); + + // When we're in the `Blocks` screen enable deep linking to the selected block. + useEffect( () => { + // Only navigate when block selection changes, not when path changes + if ( selectedBlockClientId === previousBlockClientId ) { + return; + } + if ( ! selectedBlockClientId || ! blockHasGlobalStyles ) { + return; + } + if ( + ! path || + ( path !== '/blocks' && ! path.startsWith( '/blocks/' ) ) + ) { + return; + } + const newPath = '/blocks/' + encodeURIComponent( selectedBlockName ); + // Avoid navigating to the same path. This can happen when selecting + // a new block of the same type. + if ( newPath !== path ) { + onPathChange?.( newPath ); + } + }, [ + selectedBlockClientId, + previousBlockClientId, + selectedBlockName, + blockHasGlobalStyles, + path, + onPathChange, + ] ); + + return null; +} diff --git a/packages/edit-site/src/components/global-styles/canvas-link.js b/packages/edit-site/src/components/global-styles/canvas-link.js new file mode 100644 index 00000000000000..0ee864fad4873d --- /dev/null +++ b/packages/edit-site/src/components/global-styles/canvas-link.js @@ -0,0 +1,117 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; +import { usePrevious } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { store as editSiteStore } from '../../store'; + +/** + * Synchronize editor canvas container view with global styles navigation. + * + * @param {Object} props + * @param {string} props.path Current navigation path. + * @param {Function} props.onPathChange Callback to change the navigation path. + */ +export function GlobalStylesEditorCanvasContainerLink( { + path, + onPathChange, +} ) { + const editorCanvasContainerView = useSelect( + ( select ) => + unlock( select( editSiteStore ) ).getEditorCanvasContainerView(), + [] + ); + const { setEditorCanvasContainerView } = unlock( + useDispatch( editSiteStore ) + ); + const isRevisionsOpen = path === '/revisions'; + const previousEditorCanvasContainerView = usePrevious( + editorCanvasContainerView + ); + const previousPath = usePrevious( path ); + + // If the user switches the editor canvas container view, redirect + // to the appropriate screen. This effectively allows deep linking to the + // desired screens from outside the global styles navigation provider. + useEffect( () => { + // Only trigger navigation if the view actually changed + if ( editorCanvasContainerView === previousEditorCanvasContainerView ) { + return; + } + + switch ( editorCanvasContainerView ) { + case 'global-styles-revisions': + case 'global-styles-revisions:style-book': + if ( ! isRevisionsOpen ) { + onPathChange?.( '/revisions' ); + } + break; + case 'global-styles-css': + onPathChange?.( '/css' ); + break; + // The stand-alone style book is open + // and the revisions panel is open, + // close the revisions panel. + // Otherwise keep the style book open while + // browsing global styles panel. + case 'style-book': + default: + // In general, if the revision screen is in view but the + // `editorCanvasContainerView` is not a revision view, close it. + // This also includes the scenario when the stand-alone style + // book is open, in which case we want the user to close the + // revisions screen and browse global styles. + if ( isRevisionsOpen ) { + onPathChange?.( '/' ); + } + break; + } + }, [ + editorCanvasContainerView, + previousEditorCanvasContainerView, + isRevisionsOpen, + onPathChange, + ] ); + + useEffect( () => { + // Only clear if path actually changed + if ( path === previousPath ) { + return; + } + + // If user navigated away from CSS screen, clear the canvas view + if ( previousPath === '/css' && path !== '/css' ) { + setEditorCanvasContainerView( undefined ); + } + // If user navigated away from revisions screen, clear the canvas view + else if ( + previousPath?.startsWith( '/revisions' ) && + ! path?.startsWith( '/revisions' ) && + editorCanvasContainerView && + editorCanvasContainerView.startsWith( 'global-styles-revisions' ) + ) { + // If stylebook was open with revisions, keep it open + if ( + editorCanvasContainerView === + 'global-styles-revisions:style-book' + ) { + setEditorCanvasContainerView( 'style-book' ); + } else { + setEditorCanvasContainerView( undefined ); + } + } + }, [ + path, + previousPath, + editorCanvasContainerView, + setEditorCanvasContainerView, + ] ); + + return null; +} diff --git a/packages/edit-site/src/components/global-styles/color-indicator-wrapper.js b/packages/edit-site/src/components/global-styles/color-indicator-wrapper.js deleted file mode 100644 index 242a5c77102687..00000000000000 --- a/packages/edit-site/src/components/global-styles/color-indicator-wrapper.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * External dependencies - */ -import clsx from 'clsx'; - -/** - * WordPress dependencies - */ -import { Flex } from '@wordpress/components'; - -function ColorIndicatorWrapper( { className, ...props } ) { - return ( - - ); -} - -export default ColorIndicatorWrapper; diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/make-families-from-faces.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/make-families-from-faces.js deleted file mode 100644 index 7cdbf405c0b5bc..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/make-families-from-faces.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * WordPress dependencies - */ -import { privateApis as componentsPrivateApis } from '@wordpress/components'; - -/** - * Internal dependencies - */ -import { unlock } from '../../../../lock-unlock'; - -const { kebabCase } = unlock( componentsPrivateApis ); - -export default function makeFamiliesFromFaces( fontFaces ) { - const fontFamiliesObject = fontFaces.reduce( ( acc, item ) => { - if ( ! acc[ item.fontFamily ] ) { - acc[ item.fontFamily ] = { - name: item.fontFamily, - fontFamily: item.fontFamily, - slug: kebabCase( item.fontFamily.toLowerCase() ), - fontFace: [], - }; - } - acc[ item.fontFamily ].fontFace.push( item ); - return acc; - }, {} ); - return Object.values( fontFamiliesObject ); -} diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/filter-fonts.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/filter-fonts.spec.js deleted file mode 100644 index cd32e2b68f9cd1..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/filter-fonts.spec.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Internal dependencies - */ -import filterFonts from '../filter-fonts'; - -describe( 'filterFonts', () => { - const mockFonts = [ - { - font_family_settings: { name: 'Arial' }, - categories: [ 'sans-serif' ], - }, - { - font_family_settings: { name: 'Arial Condensed' }, - categories: [ 'sans-serif' ], - }, - { - font_family_settings: { name: 'Times New Roman' }, - categories: [ 'serif' ], - }, - { - font_family_settings: { name: 'Courier New' }, - categories: [ 'monospace' ], - }, - { - font_family_settings: { name: 'Romantic' }, - categories: [ 'cursive' ], - }, - ]; - - it( 'should return all fonts if no filters are provided', () => { - const result = filterFonts( mockFonts, {} ); - expect( result ).toEqual( mockFonts ); - } ); - - it( 'should filter by category', () => { - const result = filterFonts( mockFonts, { category: 'serif' } ); - expect( result ).toEqual( [ - { - font_family_settings: { name: 'Times New Roman' }, - categories: [ 'serif' ], - }, - ] ); - } ); - - it( 'should return all fonts if category is "all"', () => { - const result = filterFonts( mockFonts, { category: 'all' } ); - expect( result ).toEqual( mockFonts ); - } ); - - it( 'should filter by search', () => { - const result = filterFonts( mockFonts, { search: 'ari' } ); - expect( result ).toEqual( [ - { - font_family_settings: { name: 'Arial' }, - categories: [ 'sans-serif' ], - }, - { - font_family_settings: { name: 'Arial Condensed' }, - categories: [ 'sans-serif' ], - }, - ] ); - } ); - - it( 'should be case insensitive when filtering by search', () => { - const result = filterFonts( mockFonts, { search: 'RoMANtic' } ); - expect( result ).toEqual( [ - { - font_family_settings: { name: 'Romantic' }, - categories: [ 'cursive' ], - }, - ] ); - } ); - - it( 'should filter by both category and search', () => { - const result = filterFonts( mockFonts, { - category: 'serif', - search: 'Times', - } ); - expect( result ).toEqual( [ - { - font_family_settings: { name: 'Times New Roman' }, - categories: [ 'serif' ], - }, - ] ); - } ); - - it( 'should return an empty array if no fonts match the filter criteria', () => { - const result = filterFonts( mockFonts, { - category: 'serif', - search: 'Arial', - } ); - expect( result ).toEqual( [] ); - } ); - - it( 'should return an empty array if fonts array is not provided', () => { - const result = filterFonts( undefined, { category: 'serif' } ); - expect( result ).toEqual( [] ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/fonts-outline.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/fonts-outline.spec.js deleted file mode 100644 index 24d9f05d028910..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/fonts-outline.spec.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Internal dependencies - */ -import { getFontsOutline, isFontFontFaceInOutline } from '../fonts-outline'; - -describe( 'getFontsOutline', () => { - test( 'should return an empty object for an empty fonts array', () => { - const fonts = []; - const result = getFontsOutline( fonts ); - expect( result ).toEqual( {} ); - } ); - - test( 'should handle fonts with no fontFace property', () => { - const fonts = [ - { slug: 'font1' }, - { - slug: 'font2', - fontFace: [ { fontStyle: 'normal', fontWeight: '400' } ], - }, - ]; - const result = getFontsOutline( fonts ); - expect( result ).toEqual( { - font1: {}, - font2: { 'normal-400': true }, - } ); - } ); - - test( 'should handle fonts with an empty fontFace array', () => { - const fonts = [ { slug: 'font1', fontFace: [] } ]; - const result = getFontsOutline( fonts ); - expect( result ).toEqual( { - font1: {}, - } ); - } ); - - test( 'should handle fonts with multiple font faces', () => { - const fonts = [ - { - slug: 'font1', - fontFace: [ - { fontStyle: 'normal', fontWeight: '400' }, - { fontStyle: 'italic', fontWeight: '700' }, - ], - }, - ]; - const result = getFontsOutline( fonts ); - expect( result ).toEqual( { - font1: { - 'normal-400': true, - 'italic-700': true, - }, - } ); - } ); -} ); - -describe( 'isFontFontFaceInOutline', () => { - test( 'should return false for an empty outline', () => { - const slug = 'font1'; - const face = { fontStyle: 'normal', fontWeight: '400' }; - const outline = {}; - - const result = isFontFontFaceInOutline( slug, face, outline ); - - expect( result ).toBe( false ); - } ); - - test( 'should return false when outline has the slug but no matching fontStyle-fontWeight', () => { - const slug = 'font1'; - const face = { fontStyle: 'normal', fontWeight: '400' }; - const outline = { - font1: { - 'italic-700': true, - }, - }; - - const result = isFontFontFaceInOutline( slug, face, outline ); - - expect( result ).toBe( false ); - } ); - - test( 'should return false when outline does not have the slug', () => { - const slug = 'font1'; - const face = { fontStyle: 'normal', fontWeight: '400' }; - const outline = { - font2: { - 'normal-400': true, - }, - }; - - const result = isFontFontFaceInOutline( slug, face, outline ); - - expect( result ).toBe( false ); - } ); - - test( 'should return true when outline has the slug and the matching fontStyle-fontWeight', () => { - const slug = 'font1'; - const face = { fontStyle: 'normal', fontWeight: '400' }; - const outline = { - font1: { - 'normal-400': true, - 'italic-700': true, - }, - }; - - const result = isFontFontFaceInOutline( slug, face, outline ); - - expect( result ).toBe( true ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getDisplaySrcFromFontFace.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getDisplaySrcFromFontFace.spec.js deleted file mode 100644 index 3cbdc0283f1a9e..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getDisplaySrcFromFontFace.spec.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Internal dependencies - */ -import { getDisplaySrcFromFontFace } from '../index'; - -describe( 'getDisplaySrcFromFontFace', () => { - it( 'returns the first item when input is an array', () => { - const input = [ - 'http://example.com/font-asset-1.ttf', - 'http://example.com/font-asset-2.ttf', - ]; - expect( getDisplaySrcFromFontFace( input ) ).toBe( - 'http://example.com/font-asset-1.ttf' - ); - } ); - - it( 'returns the input when it is a string', () => { - const input = 'http://example.com/font-asset-1.ttf'; - expect( getDisplaySrcFromFontFace( input ) ).toBe( - 'http://example.com/font-asset-1.ttf' - ); - } ); - - it( 'return undefined when the url starts with file:', () => { - const input = 'file:./theme/assets/font1.ttf'; - expect( getDisplaySrcFromFontFace( input ) ).toBe( undefined ); - } ); - - it( 'encodes the URL if it is not encoded', () => { - const input = 'https://example.org/font one with spaces.ttf'; - expect( getDisplaySrcFromFontFace( input ) ).toBe( - 'https://example.org/font%20one%20with%20spaces.ttf' - ); - } ); - - it( 'does not encode the URL if it is already encoded', () => { - const input = 'https://example.org/fonts/font%20one.ttf'; - expect( getDisplaySrcFromFontFace( input ) ).toBe( - 'https://example.org/fonts/font%20one.ttf' - ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getFontFaceVariantName.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getFontFaceVariantName.spec.js deleted file mode 100644 index 21347a342f396a..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getFontFaceVariantName.spec.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Internal dependencies - */ -import { getFontFaceVariantName } from '../index'; - -describe( 'getFontFaceVariantName', () => { - it( 'should return "Normal" for fontWeight 400 and fontStyle "normal"', () => { - const face = { fontWeight: 400, fontStyle: 'normal' }; - const result = getFontFaceVariantName( face ); - expect( result ).toBe( 'Normal ' ); - } ); - - it( 'should return "Bold Italic" for fontWeight 700 and fontStyle "italic"', () => { - const face = { fontWeight: 700, fontStyle: 'italic' }; - const result = getFontFaceVariantName( face ); - expect( result ).toBe( 'Bold Italic' ); - } ); - - it( 'should return the numerical weight when fontWeight is not recognized', () => { - const face = { fontWeight: 150, fontStyle: 'normal' }; - const result = getFontFaceVariantName( face ); - expect( result ).toBe( '150 ' ); - } ); - - it( 'should return the raw style when fontStyle is not recognized', () => { - const face = { fontWeight: 400, fontStyle: 'oblique' }; - const result = getFontFaceVariantName( face ); - expect( result ).toBe( 'Normal oblique' ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/isUrlEncoded.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/isUrlEncoded.spec.js deleted file mode 100644 index 797a8c9febd0f8..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/isUrlEncoded.spec.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Internal dependencies - */ -import { isUrlEncoded } from '../index'; - -describe( 'isUrlEncoded', () => { - // Test when input is not a string - it( 'should return false if the input is not a string', () => { - expect( isUrlEncoded( 123 ) ).toBe( false ); - expect( isUrlEncoded( null ) ).toBe( false ); - expect( isUrlEncoded( undefined ) ).toBe( false ); - expect( isUrlEncoded( {} ) ).toBe( false ); - expect( isUrlEncoded( [] ) ).toBe( false ); - } ); - - // Test when URL is not encoded - it( 'should return false for non-encoded URLs', () => { - expect( isUrlEncoded( 'http://example.com' ) ).toBe( false ); - expect( isUrlEncoded( 'https://www.google.com' ) ).toBe( false ); - expect( isUrlEncoded( '/path/to/resource' ) ).toBe( false ); - expect( isUrlEncoded( '' ) ).toBe( false ); - } ); - - // Test when URL is encoded - it( 'should return true for encoded URLs', () => { - expect( isUrlEncoded( 'http%3A%2F%2Fexample.com' ) ).toBe( true ); - expect( isUrlEncoded( 'https%3A%2F%2Fwww.google.com' ) ).toBe( true ); - expect( isUrlEncoded( '%2Fpath%2Fto%2Fresource' ) ).toBe( true ); - expect( isUrlEncoded( '%20' ) ).toBe( true ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/makeFamiliesFromFaces.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/makeFamiliesFromFaces.spec.js deleted file mode 100644 index b8e147116ea6ac..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/makeFamiliesFromFaces.spec.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Internal dependencies - */ -import makeFamiliesFromFaces from '../make-families-from-faces'; - -describe( 'makeFamiliesFromFaces', () => { - it( 'handles empty fontFaces list', () => { - const result = makeFamiliesFromFaces( [] ); - expect( result ).toEqual( [] ); - } ); - - it( 'groups fontFaces by fontFamily', () => { - const fontFaces = [ - { fontFamily: 'Lobster' }, - { - fontFamily: 'Piazzolla', - file: { name: 'piazzolla.ttf' }, - }, - { fontFamily: 'Lobster', file: { name: 'piazzolla.ttf' } }, - ]; - - const result = makeFamiliesFromFaces( fontFaces ); - - expect( result ).toHaveLength( 2 ); - expect( - result.find( ( family ) => family.name === 'Lobster' ).fontFace - ).toHaveLength( 2 ); - expect( - result.find( ( family ) => family.name === 'Piazzolla' ).fontFace - ).toHaveLength( 1 ); - } ); - - it( 'generates correct name for fontFamily names', () => { - const fontFaces = [ - { - fontFamily: 'Piazzolla', - file: { name: 'piazzolla.ttf' }, - }, - ]; - - const result = makeFamiliesFromFaces( fontFaces ); - expect( result[ 0 ].name ).toBe( 'Piazzolla' ); - } ); - - it( 'generates correct slug for fontFamily names', () => { - const fontFaces = [ - { - fontFamily: 'Times New Roman', - file: { name: 'times.ttf' }, - }, - ]; - - const result = makeFamiliesFromFaces( fontFaces ); - - expect( result[ 0 ].slug ).toBe( 'times-new-roman' ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/mergeFontFaces.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/mergeFontFaces.spec.js deleted file mode 100644 index ea5f2b0353ee9b..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/mergeFontFaces.spec.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Internal dependencies - */ -import { mergeFontFaces } from '../index'; - -describe( 'mergeFontFaces', () => { - it( 'should return an empty array when both existing and incoming arrays are empty', () => { - expect( mergeFontFaces() ).toEqual( [] ); - } ); - - it( 'should return the existing array when the incoming array is empty', () => { - const existing = [ { fontWeight: 'normal', fontStyle: 'italic' } ]; - expect( mergeFontFaces( existing, [] ) ).toEqual( existing ); - } ); - - it( 'should return the incoming array when the existing array is empty', () => { - const incoming = [ { fontWeight: 'bold', fontStyle: 'normal' } ]; - expect( mergeFontFaces( [], incoming ) ).toEqual( incoming ); - } ); - - it( 'should merge non-overlapping existing and incoming arrays', () => { - const existing = [ { fontWeight: 'normal', fontStyle: 'italic' } ]; - const incoming = [ { fontWeight: 'bold', fontStyle: 'normal' } ]; - expect( mergeFontFaces( existing, incoming ) ).toEqual( [ - ...existing, - ...incoming, - ] ); - } ); - - it( 'should overwrite duplicates with the incoming array', () => { - const existing = [ - { fontWeight: 'normal', fontStyle: 'italic', src: 'old-src' }, - ]; - const incoming = [ - { fontWeight: 'normal', fontStyle: 'italic', src: 'new-src' }, - ]; - expect( mergeFontFaces( existing, incoming ) ).toEqual( incoming ); - } ); - - it( 'should handle multiple elements in both existing and incoming arrays', () => { - const existing = [ - { fontWeight: 'normal', fontStyle: 'italic', src: 'old-1' }, - { fontWeight: 'bold', fontStyle: 'normal', src: 'old-2' }, - ]; - const incoming = [ - { fontWeight: 'normal', fontStyle: 'italic', src: 'new-1' }, - { fontWeight: 'bold', fontStyle: 'oblique', src: 'new-2' }, - ]; - const expected = [ - { fontWeight: 'normal', fontStyle: 'italic', src: 'new-1' }, - { fontWeight: 'bold', fontStyle: 'normal', src: 'old-2' }, - { fontWeight: 'bold', fontStyle: 'oblique', src: 'new-2' }, - ]; - expect( mergeFontFaces( existing, incoming ) ).toEqual( expected ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/mergeFontFamilies.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/mergeFontFamilies.spec.js deleted file mode 100644 index 5779534dfa9257..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/mergeFontFamilies.spec.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Internal dependencies - */ -import { mergeFontFamilies } from '../index'; - -describe( 'mergeFontFamilies', () => { - it( 'should return an empty array when both inputs are empty', () => { - const result = mergeFontFamilies( [], [] ); - expect( result ).toEqual( [] ); - } ); - - it( 'should return the existing array when incoming array is empty', () => { - const existing = [ - { slug: 'lobster', name: 'Lobster', fontFamily: 'Lobster' }, - ]; - const result = mergeFontFamilies( existing, [] ); - expect( result ).toEqual( existing ); - } ); - - it( 'should concar non-conflicting arrays', () => { - const existing = [ - { slug: 'lobster', name: 'Lobster', fontFamily: 'Lobster' }, - ]; - const incoming = [ - { slug: 'piazzola', name: 'Piazzolla', fontFamily: 'Piazzolla' }, - ]; - const result = mergeFontFamilies( existing, incoming ); - expect( result ).toEqual( [ ...existing, ...incoming ] ); - } ); - - it( 'should merge non-conflicting arrays', () => { - const existing = [ - { slug: 'lobster', name: 'Lobster', fontFamily: 'Lobster' }, - { slug: 'piazzola', name: 'Piazzolla', fontFamily: 'Piazzolla' }, - ]; - const incoming = [ - { slug: 'piazzola', name: 'Piazzolla', fontFamily: 'Piazzolla' }, - ]; - const result = mergeFontFamilies( existing, incoming ); - expect( result ).toHaveLength( 2 ); - } ); - - it( 'should overwrite existing font family data with incoming data', () => { - const existing = [ - { slug: 'lobster', name: 'Lobster', fontFamily: 'Lobster' }, - { slug: 'piazzola', name: 'Piazzolla', fontFamily: 'Piazzolla' }, - ]; - const incoming = [ - { - slug: 'piazzola', - name: 'Piazzolla', - fontFamily: 'Piazzolla, serif', - }, - ]; - const result = mergeFontFamilies( existing, incoming ); - expect( result[ 1 ].fontFamily ).toBe( 'Piazzolla, serif' ); - } ); - - it( 'should merge fontFaces from incoming array', () => { - const existing = [ - { - slug: 'lobster', - name: 'Lobster', - fontFamily: 'Lobster', - }, - { - slug: 'piazzola', - name: 'Piazzolla', - fontFamily: 'Piazzolla', - fontFace: [ - { fontWeight: 400, fontStyle: 'normal', src: 'url' }, - { fontWeight: 500, fontStyle: 'normal', src: 'url' }, - ], - }, - ]; - const incoming = [ - { - slug: 'piazzola', - name: 'Piazzolla', - fontFamily: 'Piazzolla, serif', - fontFace: [ - { fontWeight: 800, fontStyle: 'normal', src: 'url' }, - { fontWeight: 400, fontStyle: 'normal', src: 'url' }, - ], - }, - ]; - const expected = [ - { - slug: 'lobster', - name: 'Lobster', - fontFamily: 'Lobster', - }, - { - slug: 'piazzola', - name: 'Piazzolla', - fontFamily: 'Piazzolla, serif', - fontFace: [ - { fontWeight: 400, fontStyle: 'normal', src: 'url' }, - { fontWeight: 500, fontStyle: 'normal', src: 'url' }, - { fontWeight: 800, fontStyle: 'normal', src: 'url' }, - ], - }, - ]; - - const result = mergeFontFamilies( existing, incoming ); - expect( result ).toEqual( expected ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/preview-styles.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/preview-styles.spec.js deleted file mode 100644 index a2dc7e63d14a92..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/preview-styles.spec.js +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Internal dependencies - */ -import { - getFamilyPreviewStyle, - formatFontFamily, - formatFontFaceName, -} from '../preview-styles'; - -describe( 'getFamilyPreviewStyle', () => { - it( 'should return default fontStyle and fontWeight if fontFace is not provided', () => { - const family = { fontFamily: 'Rosario' }; - const result = getFamilyPreviewStyle( family ); - const expected = { - fontFamily: 'Rosario', - fontWeight: '400', - fontStyle: 'normal', - }; - expect( result ).toEqual( expected ); - } ); - - it( 'should return fontStyle as "normal" if fontFace contains "normal" style', () => { - const family = { - fontFamily: 'Rosario', - fontFace: [ - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'normal', fontWeight: '600' }, - ], - }; - const result = getFamilyPreviewStyle( family ); - const expected = { - fontFamily: 'Rosario', - fontStyle: 'normal', - fontWeight: '600', - }; - expect( result ).toEqual( expected ); - } ); - - it( 'should return fontStyle as "itaic" if fontFace does not contain "normal" style', () => { - const family = { - fontFamily: 'Rosario', - fontFace: [ - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'italic', fontWeight: '600' }, - ], - }; - const result = getFamilyPreviewStyle( family ); - const expected = { - fontFamily: 'Rosario', - fontStyle: 'italic', - fontWeight: '500', - }; - expect( result ).toEqual( expected ); - } ); - - it( 'should return fontWeight as string', () => { - const family = { - fontFamily: 'Rosario', - fontFace: [ - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'normal', fontWeight: '700' }, - ], - }; - const result = getFamilyPreviewStyle( family ); - const expected = { - fontFamily: 'Rosario', - fontStyle: 'normal', - fontWeight: '700', - }; - expect( result ).toEqual( expected ); - } ); - - it( 'should return fontWeight as "400" if fontFace contains "normal" style with "400" weight', () => { - const family = { - fontFamily: 'Rosario', - fontFace: [ - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'normal', fontWeight: '400' }, - ], - }; - const result = getFamilyPreviewStyle( family ); - const expected = { - fontFamily: 'Rosario', - fontStyle: 'normal', - fontWeight: '400', - }; - expect( result ).toEqual( expected ); - } ); - - it( 'should return the fontWeight of the nearest "normal" style if no "400" weight is found', () => { - const family = { - fontFamily: 'Rosario', - fontFace: [ - { fontStyle: 'normal', fontWeight: '800' }, - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'normal', fontWeight: '600' }, - ], - }; - const result = getFamilyPreviewStyle( family ); - const expected = { - fontFamily: 'Rosario', - fontStyle: 'normal', - fontWeight: '600', - }; - expect( result ).toEqual( expected ); - } ); - - it( 'should return 400 or the the nearest "normal" style if it using a variable weight font', () => { - const family = { - fontFamily: 'Rosario', - fontFace: [ - { fontStyle: 'normal', fontWeight: '100' }, - { fontStyle: 'normal', fontWeight: '200 900' }, - { fontStyle: 'italic', fontWeight: '200 900' }, - ], - }; - const result = getFamilyPreviewStyle( family ); - const expected = { - fontFamily: 'Rosario', - fontStyle: 'normal', - fontWeight: '400', - }; - expect( result ).toEqual( expected ); - } ); -} ); - -describe( 'formatFontFamily', () => { - it( 'should transform "Baloo 2, system-ui" correctly', () => { - expect( formatFontFamily( 'Baloo 2, system-ui' ) ).toBe( - '"Baloo 2", system-ui' - ); - } ); - - it( 'should ignore extra spaces', () => { - expect( formatFontFamily( ' Baloo 2 , system-ui' ) ).toBe( - '"Baloo 2", system-ui' - ); - } ); - - it( 'should keep quoted strings unchanged', () => { - expect( - formatFontFamily( - "Seravek, 'Gill Sans Nova', Ubuntu, Calibri, 'DejaVu Sans', source-sans-pro, sans-serif" - ) - ).toBe( - 'Seravek, "Gill Sans Nova", Ubuntu, Calibri, "DejaVu Sans", source-sans-pro, sans-serif' - ); - } ); - - it( 'should wrap single font name with spaces in quotes', () => { - expect( formatFontFamily( 'Baloo 2' ) ).toBe( '"Baloo 2"' ); - } ); - - it( 'should wrap multiple font names with spaces in quotes', () => { - expect( formatFontFamily( 'Baloo Bhai 2, Baloo 2' ) ).toBe( - '"Baloo Bhai 2", "Baloo 2"' - ); - } ); - - it( 'should wrap names with special characters in quotes', () => { - expect( - formatFontFamily( - 'Font+Name, Font*Name, _Font_Name_, generic(kai), sans-serif' - ) - ).toBe( - '"Font+Name", "Font*Name", "_Font_Name_", generic(kai), sans-serif' - ); - } ); - - it( 'should fix empty wrong formatted font family', () => { - expect( formatFontFamily( ', Abril Fatface,Times,serif' ) ).toBe( - '"Abril Fatface", Times, serif' - ); - } ); - - it( 'should not add quotes to generic names', () => { - expect( - formatFontFamily( - 'Paren(thesis)Font, generic(kai), generic(fasongsong), generic( abc ), Helvetica Neue' - ) - ).toBe( - '"Paren(thesis)Font", generic(kai), generic(fasongsong), generic( abc ), "Helvetica Neue"' - ); - } ); -} ); - -describe( 'formatFontFaceName', () => { - it( 'should remove leading and trailing quotes', () => { - expect( formatFontFaceName( '"Open Sans"' ) ).toBe( 'Open Sans' ); - } ); - - it( 'should remove leading and trailing quotes from multiple font face names', () => { - expect( - formatFontFaceName( "'Open Sans', 'Helvetica Neue', sans-serif" ) - ).toBe( 'Open Sans' ); - } ); - - it( 'should remove leading and trailing quotes even from names with spaces and special characters', () => { - expect( formatFontFaceName( "'Font+Name 24', sans-serif" ) ).toBe( - 'Font+Name 24' - ); - } ); - - it( 'should output the font face name with quotes on Firefox', () => { - const mockUserAgent = - 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0'; - - // Mock the userAgent for this test - Object.defineProperty( window.navigator, 'userAgent', { - value: mockUserAgent, - configurable: true, - } ); - - expect( formatFontFaceName( 'Open Sans' ) ).toBe( '"Open Sans"' ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/setUIValuesNeeded.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/setUIValuesNeeded.spec.js deleted file mode 100644 index be167cb3eb34de..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/setUIValuesNeeded.spec.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Internal dependencies - */ -import { setUIValuesNeeded } from '../index'; - -describe( 'setUIValuesNeeded function', () => { - test( 'Should set name from fontFamily if name is missing', () => { - const font = { fontFamily: 'Arial' }; - const result = setUIValuesNeeded( font ); - expect( result.name ).toBe( 'Arial' ); - } ); - - test( 'Should set name from slug if name and fontFamily are missing', () => { - const font = { slug: 'arial-slug' }; - const result = setUIValuesNeeded( font ); - expect( result.name ).toBe( 'arial-slug' ); - } ); - - test( 'Should not overwrite name if it exists', () => { - const font = { name: 'ExistingName', fontFamily: 'Arial' }; - const result = setUIValuesNeeded( font ); - expect( result.name ).toBe( 'ExistingName' ); - } ); - - test( 'Should merge extra values', () => { - const font = { name: 'Arial', slug: 'arial' }; - const extraValues = { source: 'custom' }; - const result = setUIValuesNeeded( font, extraValues ); - expect( result ).toEqual( { - name: 'Arial', - slug: 'arial', - source: 'custom', - } ); - } ); - - test( 'Should return the same object if no conditions met', () => { - const font = { randomProperty: 'randomValue' }; - const result = setUIValuesNeeded( font ); - expect( result ).toEqual( font ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/sort-font-faces.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/sort-font-faces.js deleted file mode 100644 index 7f81b57a77f665..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/sort-font-faces.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Internal dependencies - */ -import { sortFontFaces } from '../sort-font-faces'; - -describe( 'sortFontFaces', () => { - it( 'should prioritize "normal" fontStyle and then sort by numeric fontWeight values', () => { - const input = [ - { fontStyle: 'normal', fontWeight: '500' }, - { fontStyle: 'normal', fontWeight: '400' }, - ]; - const expected = [ - { fontStyle: 'normal', fontWeight: '400' }, - { fontStyle: 'normal', fontWeight: '500' }, - ]; - expect( sortFontFaces( input ) ).toEqual( expected ); - } ); - - it( 'should correctly sort named fontWeight values within the same fontStyle', () => { - const input = [ - { fontStyle: 'italic', fontWeight: 'bold' }, - { fontStyle: 'italic', fontWeight: 'normal' }, - ]; - const expected = [ - { fontStyle: 'italic', fontWeight: 'normal' }, - { fontStyle: 'italic', fontWeight: 'bold' }, - ]; - expect( sortFontFaces( input ) ).toEqual( expected ); - } ); - - it( 'should prioritize fontStyle "normal" over other styles', () => { - const input = [ - { fontStyle: 'italic', fontWeight: '400' }, - { fontStyle: 'normal', fontWeight: '500' }, - ]; - const expected = [ - { fontStyle: 'normal', fontWeight: '500' }, - { fontStyle: 'italic', fontWeight: '400' }, - ]; - expect( sortFontFaces( input ) ).toEqual( expected ); - } ); - - it( 'should sort other fontStyles alphabetically after "normal"', () => { - const input = [ - { fontStyle: 'oblique', fontWeight: '500' }, - { fontStyle: 'italic', fontWeight: '500' }, - ]; - const expected = [ - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'oblique', fontWeight: '500' }, - ]; - expect( sortFontFaces( input ) ).toEqual( expected ); - } ); - - it( 'should correctly handle multiple test cases', () => { - const input = [ - { fontStyle: 'oblique', fontWeight: '300' }, - { fontStyle: 'normal', fontWeight: '400' }, - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'italic', fontWeight: 'bold' }, - { fontStyle: 'italic', fontWeight: '600 900' }, - { fontStyle: 'normal', fontWeight: '500' }, - ]; - const expected = [ - { fontStyle: 'normal', fontWeight: '400' }, - { fontStyle: 'normal', fontWeight: '500' }, - { fontStyle: 'italic', fontWeight: '500' }, - { fontStyle: 'italic', fontWeight: '600 900' }, - { fontStyle: 'italic', fontWeight: 'bold' }, - { fontStyle: 'oblique', fontWeight: '300' }, - ]; - expect( sortFontFaces( input ) ).toEqual( expected ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/toggleFont.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/toggleFont.spec.js deleted file mode 100644 index 509a2145bbc436..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/toggleFont.spec.js +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Internal dependencies - */ -import { toggleFont } from '../toggleFont'; - -describe( 'toggleFont function', () => { - const initialCustomFonts = [ - { - slug: 'font1', - fontFace: [ - { fontWeight: '400', fontStyle: 'normal' }, - { fontWeight: '700', fontStyle: 'italic' }, - ], - }, - ]; - - const newFont = { slug: 'font2', fontFace: [] }; - - // Basic Toggles - describe( 'Basic Toggles', () => { - it( 'should toggle the entire font family on/off', () => { - let updatedFonts = toggleFont( newFont, null, initialCustomFonts ); - expect( updatedFonts ).toEqual( [ - ...initialCustomFonts, - newFont, - ] ); - - updatedFonts = toggleFont( newFont, null, updatedFonts ); - expect( updatedFonts ).toEqual( initialCustomFonts ); - } ); - - it( 'should toggle a specific font face of an activated font family', () => { - const face = { fontWeight: '400', fontStyle: 'normal' }; - let updatedFonts = toggleFont( - initialCustomFonts[ 0 ], - face, - initialCustomFonts - ); - expect( updatedFonts[ 0 ].fontFace ).toEqual( [ - { fontWeight: '700', fontStyle: 'italic' }, - ] ); - - updatedFonts = toggleFont( - initialCustomFonts[ 0 ], - face, - updatedFonts - ); - expect( updatedFonts[ 0 ].fontFace ).toEqual( [ - { fontWeight: '700', fontStyle: 'italic' }, - { fontWeight: '400', fontStyle: 'normal' }, - ] ); - } ); - - it( 'should toggle a specific font face of a non-activated font family', () => { - const face = { fontWeight: '500', fontStyle: 'normal' }; - const updatedFonts = toggleFont( - newFont, - face, - initialCustomFonts - ); - expect( updatedFonts ).toEqual( [ - ...initialCustomFonts, - { ...newFont, fontFace: [ face ] }, - ] ); - } ); - } ); - - // Edge Cases - describe( 'Edge Cases', () => { - it( 'should handle empty initial fonts', () => { - const updatedFonts = toggleFont( newFont, null, [] ); - expect( updatedFonts ).toEqual( [ newFont ] ); - } ); - - it( 'should deactivate font family when all font faces are deactivated', () => { - const face1 = { fontWeight: '400', fontStyle: 'normal' }; - const face2 = { fontWeight: '700', fontStyle: 'italic' }; - let updatedFonts = toggleFont( - initialCustomFonts[ 0 ], - face1, - initialCustomFonts - ); - updatedFonts = toggleFont( - initialCustomFonts[ 0 ], - face2, - updatedFonts - ); - - expect( updatedFonts ).toEqual( [] ); - } ); - - it( 'should not duplicate an already activated font face', () => { - const face = { fontWeight: '400', fontStyle: 'normal' }; - const updatedFonts = toggleFont( - initialCustomFonts[ 0 ], - face, - initialCustomFonts - ); - const furtherUpdatedFonts = toggleFont( - initialCustomFonts[ 0 ], - face, - updatedFonts - ); - - expect( furtherUpdatedFonts ).toHaveLength( 1 ); - // Sort the font faces by fontWeight to ensure the order is consistent for the toEqual assertion. - expect( - furtherUpdatedFonts[ 0 ].fontFace.sort( - ( a, b ) => a.fontWeight - b.fontWeight - ) - ).toEqual( initialCustomFonts[ 0 ].fontFace ); - } ); - - it( 'should handle undefined or null fontFace gracefully', () => { - const fontWithoutFaces = { slug: 'font3' }; // no fontFace defined - const face = { fontWeight: '500', fontStyle: 'normal' }; - const updatedFonts = toggleFont( - fontWithoutFaces, - face, - initialCustomFonts - ); - expect( updatedFonts ).toEqual( [ - ...initialCustomFonts, - { ...fontWithoutFaces, fontFace: [ face ] }, - ] ); - } ); - - it( 'should handle fonts with the same slug but different properties', () => { - const differentFontWithSameSlug = { - slug: 'font1', - displayName: 'Different Font with Same Slug', - }; - const updatedFonts = toggleFont( - differentFontWithSameSlug, - null, - initialCustomFonts - ); - expect( updatedFonts ).toEqual( [] ); - } ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/font-sizes/font-size-preview.js b/packages/edit-site/src/components/global-styles/font-sizes/font-size-preview.js deleted file mode 100644 index e49ed0249e65a4..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-sizes/font-size-preview.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * WordPress dependencies - */ -import { - getComputedFluidTypographyValue, - privateApis as blockEditorPrivateApis, -} from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; - -/** - * Internal dependencies - */ -import { unlock } from '../../../lock-unlock'; -const { useGlobalStyle } = unlock( blockEditorPrivateApis ); - -function FontSizePreview( { fontSize } ) { - const [ font ] = useGlobalStyle( 'typography' ); - - const input = - fontSize?.fluid?.min && fontSize?.fluid?.max - ? { - minimumFontSize: fontSize.fluid.min, - maximumFontSize: fontSize.fluid.max, - } - : { - fontSize: fontSize.size, - }; - - const computedFontSize = getComputedFluidTypographyValue( input ); - return ( -
- { __( 'Aa' ) } -
- ); -} - -export default FontSizePreview; diff --git a/packages/edit-site/src/components/global-styles/hooks.js b/packages/edit-site/src/components/global-styles/hooks.js index ccae419be98c00..77bb6cdecadb68 100644 --- a/packages/edit-site/src/components/global-styles/hooks.js +++ b/packages/edit-site/src/components/global-styles/hooks.js @@ -1,111 +1,216 @@ -/** - * External dependencies - */ -import { colord, extend } from 'colord'; -import a11yPlugin from 'colord/plugins/a11y'; - /** * WordPress dependencies */ -import { store as blocksStore } from '@wordpress/blocks'; +import { useMemo, useCallback } from '@wordpress/element'; +import { + mergeGlobalStyles, + getStyle, + getSetting, +} from '@wordpress/global-styles-engine'; +import { store as coreStore } from '@wordpress/core-data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; /** * Internal dependencies */ import { unlock } from '../../lock-unlock'; -import { useSelect } from '@wordpress/data'; -const { useGlobalSetting, useGlobalStyle } = unlock( blockEditorPrivateApis ); +const { cleanEmptyObject } = unlock( blockEditorPrivateApis ); -// Enable colord's a11y plugin. -extend( [ a11yPlugin ] ); - -export function useColorRandomizer( name ) { - const [ themeColors, setThemeColors ] = useGlobalSetting( - 'color.palette.theme', - name - ); - - function randomizeColors() { - /* eslint-disable no-restricted-syntax */ - const randomRotationValue = Math.floor( Math.random() * 225 ); - /* eslint-enable no-restricted-syntax */ - - const newColors = themeColors.map( ( colorObject ) => { - const { color } = colorObject; - const newColor = colord( color ) - .rotate( randomRotationValue ) - .toHex(); +/** + * Hook to fetch and manage user global styles config + */ +function useGlobalStylesUserConfig() { + const { globalStylesId, isReady, settings, styles, _links } = useSelect( + ( select ) => { + const { + getEntityRecord, + getEditedEntityRecord, + hasFinishedResolution, + canUser, + } = select( coreStore ); + const _globalStylesId = + select( coreStore ).__experimentalGetCurrentGlobalStylesId(); + + let record; + + const userCanEditGlobalStyles = _globalStylesId + ? canUser( 'update', { + kind: 'root', + name: 'globalStyles', + id: _globalStylesId, + } ) + : null; + + if ( + _globalStylesId && + typeof userCanEditGlobalStyles === 'boolean' + ) { + if ( userCanEditGlobalStyles ) { + record = getEditedEntityRecord( + 'root', + 'globalStyles', + _globalStylesId + ); + } else { + record = getEntityRecord( + 'root', + 'globalStyles', + _globalStylesId, + { context: 'view' } + ); + } + } + + let hasResolved = false; + if ( + hasFinishedResolution( + '__experimentalGetCurrentGlobalStylesId' + ) + ) { + if ( _globalStylesId ) { + hasResolved = userCanEditGlobalStyles + ? hasFinishedResolution( 'getEditedEntityRecord', [ + 'root', + 'globalStyles', + _globalStylesId, + ] ) + : hasFinishedResolution( 'getEntityRecord', [ + 'root', + 'globalStyles', + _globalStylesId, + { context: 'view' }, + ] ); + } else { + hasResolved = true; + } + } return { - ...colorObject, - color: newColor, + globalStylesId: _globalStylesId, + isReady: hasResolved, + settings: record?.settings, + styles: record?.styles, + _links: record?._links, }; - } ); - - setThemeColors( newColors ); - } - - return window.__experimentalEnableColorRandomizer - ? [ randomizeColors ] - : []; -} - -export function useStylesPreviewColors() { - const [ textColor = 'black' ] = useGlobalStyle( 'color.text' ); - const [ backgroundColor = 'white' ] = useGlobalStyle( 'color.background' ); - const [ headingColor = textColor ] = useGlobalStyle( - 'elements.h1.color.text' - ); - const [ linkColor = headingColor ] = useGlobalStyle( - 'elements.link.color.text' + }, + [] ); - const [ buttonBackgroundColor = linkColor ] = useGlobalStyle( - 'elements.button.color.background' + const { getEditedEntityRecord } = useSelect( coreStore ); + const { editEntityRecord } = useDispatch( coreStore ); + + const config = useMemo( () => { + return { + settings: settings ?? {}, + styles: styles ?? {}, + _links: _links ?? {}, + }; + }, [ settings, styles, _links ] ); + + const setConfig = useCallback( + ( callbackOrObject, options = {} ) => { + const record = getEditedEntityRecord( + 'root', + 'globalStyles', + globalStylesId + ); + + const currentConfig = { + styles: record?.styles ?? {}, + settings: record?.settings ?? {}, + _links: record?._links ?? {}, + }; + + const updatedConfig = + typeof callbackOrObject === 'function' + ? callbackOrObject( currentConfig ) + : callbackOrObject; + + editEntityRecord( + 'root', + 'globalStyles', + globalStylesId, + { + styles: cleanEmptyObject( updatedConfig.styles ) || {}, + settings: cleanEmptyObject( updatedConfig.settings ) || {}, + _links: cleanEmptyObject( updatedConfig._links ) || {}, + }, + options + ); + }, + [ globalStylesId, editEntityRecord, getEditedEntityRecord ] ); - const [ coreColors ] = useGlobalSetting( 'color.palette.core' ); - const [ themeColors ] = useGlobalSetting( 'color.palette.theme' ); - const [ customColors ] = useGlobalSetting( 'color.palette.custom' ); - const paletteColors = ( themeColors ?? [] ) - .concat( customColors ?? [] ) - .concat( coreColors ?? [] ); + return [ isReady, config, setConfig ]; +} - const textColorObject = paletteColors.filter( - ( { color } ) => color === textColor - ); - const buttonBackgroundColorObject = paletteColors.filter( - ( { color } ) => color === buttonBackgroundColor +/** + * Hook to fetch base/theme global styles config + */ +function useGlobalStylesBaseConfig() { + const baseConfig = useSelect( + ( select ) => + select( coreStore ).__experimentalGetCurrentThemeBaseGlobalStyles(), + [] ); + return [ !! baseConfig, baseConfig ]; +} - const highlightedColors = textColorObject - .concat( buttonBackgroundColorObject ) - .concat( paletteColors ) - .filter( - // we exclude these background color because it is already visible in the preview. - ( { color } ) => color !== backgroundColor - ) - .slice( 0, 2 ); +/** + * Hook to get merged global styles configuration + * + * @return {Object} Object containing merged, base, user configs and setUser function + * { merged, base, user, setUser } + */ +export function useGlobalStyles() { + const [ isUserConfigReady, userConfig, setUserConfig ] = + useGlobalStylesUserConfig(); + const [ isBaseConfigReady, baseConfig ] = useGlobalStylesBaseConfig(); + + const merged = useMemo( () => { + if ( ! isUserConfigReady || ! isBaseConfigReady ) { + return {}; + } + return mergeGlobalStyles( baseConfig || {}, userConfig ); + }, [ isUserConfigReady, isBaseConfigReady, baseConfig, userConfig ] ); return { - paletteColors, - highlightedColors, + merged, + base: baseConfig || {}, + user: userConfig, + setUser: setUserConfig, + isReady: isUserConfigReady && isBaseConfigReady, }; } -export function useSupportedStyles( name, element ) { - const { supportedPanels } = useSelect( - ( select ) => { - return { - supportedPanels: unlock( - select( blocksStore ) - ).getSupportedStyles( name, element ), - }; - }, - [ name, element ] +/** + * Hook to get a style value from global styles + * + * @param {string} path Style path (e.g., 'color.background') + * @param {string} blockName Optional block name + * @return {*} Style value + */ +export function useStyle( path, blockName ) { + const { merged } = useGlobalStyles(); + return useMemo( + () => getStyle( merged, path, blockName ), + [ merged, path, blockName ] ); +} - return supportedPanels; +/** + * Hook to get a setting value from global styles + * + * @param {string} path Setting path (e.g., 'spacing.blockGap') + * @param {string} blockName Optional block name + * @return {*} Setting value + */ +export function useSetting( path, blockName ) { + const { merged } = useGlobalStyles(); + return useMemo( + () => getSetting( merged, path, blockName ), + [ merged, path, blockName ] + ); } diff --git a/packages/edit-site/src/components/global-styles/icon-with-current-color.js b/packages/edit-site/src/components/global-styles/icon-with-current-color.js deleted file mode 100644 index 2c6f2245c84259..00000000000000 --- a/packages/edit-site/src/components/global-styles/icon-with-current-color.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * External dependencies - */ -import clsx from 'clsx'; - -/** - * WordPress dependencies - */ -import { Icon } from '@wordpress/components'; - -export function IconWithCurrentColor( { className, ...props } ) { - return ( - - ); -} diff --git a/packages/edit-site/src/components/global-styles/index.js b/packages/edit-site/src/components/global-styles/index.js index 5533852c1ac68b..07e1d34bff718f 100644 --- a/packages/edit-site/src/components/global-styles/index.js +++ b/packages/edit-site/src/components/global-styles/index.js @@ -1 +1,137 @@ -export { default as GlobalStylesUI } from './ui'; +/** + * WordPress dependencies + */ +import { store as coreStore } from '@wordpress/core-data'; +import { store as editorStore } from '@wordpress/editor'; +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; +import { GlobalStylesUI } from '@wordpress/global-styles-ui'; +import { uploadMedia } from '@wordpress/media-utils'; + +/** + * Internal dependencies + */ +import { GlobalStylesStyleBook } from './style-book-integration'; +import { GlobalStylesRevisions } from './revisions-integration'; +import { GlobalStylesBlockLink } from './block-link'; +import { GlobalStylesEditorCanvasContainerLink } from './canvas-link'; +import { useGlobalStyles } from './hooks'; + +/** + * Hook to fetch server CSS and settings for BlockEditorProvider that are not Global Styles. + */ +function useServerData() { + const { + styles, + __unstableResolvedAssets, + colors, + gradients, + __experimentalDiscussionSettings, + mediaUploadHandler, + fontLibraryEnabled, + } = useSelect( ( select ) => { + const { getEditorSettings } = select( editorStore ); + const { canUser } = select( coreStore ); + const editorSettings = getEditorSettings(); + + const canUserUploadMedia = canUser( 'create', { + kind: 'root', + name: 'media', + } ); + + return { + styles: editorSettings?.styles || [], + __unstableResolvedAssets: + editorSettings?.__unstableResolvedAssets || {}, + colors: editorSettings?.colors || [], + gradients: editorSettings?.gradients || [], + __experimentalDiscussionSettings: + editorSettings?.__experimentalDiscussionSettings, + mediaUploadHandler: canUserUploadMedia ? uploadMedia : undefined, + fontLibraryEnabled: editorSettings?.fontLibraryEnabled ?? true, + }; + }, [] ); + + // Filter out global styles to get only server-provided styles + const serverCSS = useMemo( () => { + if ( ! styles ) { + return []; + } + return styles.filter( ( style ) => ! style.isGlobalStyles ); + }, [ styles ] ); + + // Create server settings object + const serverSettings = useMemo( () => { + return { + __unstableResolvedAssets, + settings: { + color: { + palette: { + theme: colors, + }, + gradients: { + theme: gradients, + }, + duotone: { + theme: [], + }, + }, + }, + __experimentalDiscussionSettings, + mediaUpload: mediaUploadHandler, + }; + }, [ + __unstableResolvedAssets, + colors, + gradients, + __experimentalDiscussionSettings, + mediaUploadHandler, + ] ); + + return { serverCSS, serverSettings, fontLibraryEnabled }; +} + +export default function GlobalStylesUIWrapper( { path, onPathChange } ) { + const { + user: userConfig, + base: baseConfig, + setUser: setUserConfig, + isReady, + } = useGlobalStyles(); + const { serverCSS, serverSettings, fontLibraryEnabled } = useServerData(); + + // Show loading state while data is being fetched + if ( ! isReady ) { + return null; + } + + return ( + <> + + + + + + + ); +} + +export { useGlobalStyles, useStyle, useSetting } from './hooks'; diff --git a/packages/edit-site/src/components/global-styles/menu.js b/packages/edit-site/src/components/global-styles/menu.js new file mode 100644 index 00000000000000..81120b20825158 --- /dev/null +++ b/packages/edit-site/src/components/global-styles/menu.js @@ -0,0 +1,96 @@ +/** + * WordPress dependencies + */ +import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { store as preferencesStore } from '@wordpress/preferences'; +import { moreVertical } from '@wordpress/icons'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { store as editSiteStore } from '../../store'; +import { useGlobalStyles } from './hooks'; + +/** + * Action menu with Reset, Welcome Guide, and Additional CSS + */ +export function GlobalStylesActionMenu() { + const { user, setUser } = useGlobalStyles(); + + // Check if there are user customizations that can be reset + const canReset = + !! user && + ( Object.keys( user?.styles ?? {} ).length > 0 || + Object.keys( user?.settings ?? {} ).length > 0 ); + + // Reset function to clear all user customizations + const onReset = () => { + setUser( { styles: {}, settings: {} } ); + }; + const { toggle } = useDispatch( preferencesStore ); + const { canEditCSS } = useSelect( ( select ) => { + const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = + select( coreStore ); + + const globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const globalStyles = globalStylesId + ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) + : undefined; + + return { + canEditCSS: !! globalStyles?._links?.[ 'wp:action-edit-css' ], + }; + }, [] ); + const { setEditorCanvasContainerView } = unlock( + useDispatch( editSiteStore ) + ); + const loadCustomCSS = () => { + setEditorCanvasContainerView( 'global-styles-css' ); + }; + + return ( + + { ( { onClose } ) => ( + <> + + { canEditCSS && ( + + { __( 'Additional CSS' ) } + + ) } + { + toggle( + 'core/edit-site', + 'welcomeGuideStyles' + ); + onClose(); + } } + > + { __( 'Welcome Guide' ) } + + + + { + onReset(); + onClose(); + } } + disabled={ ! canReset } + > + { __( 'Reset styles' ) } + + + + ) } + + ); +} diff --git a/packages/edit-site/src/components/global-styles/revisions-integration.js b/packages/edit-site/src/components/global-styles/revisions-integration.js new file mode 100644 index 00000000000000..842f456bf0bef3 --- /dev/null +++ b/packages/edit-site/src/components/global-styles/revisions-integration.js @@ -0,0 +1,70 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; +import { useGlobalStylesRevisions } from '@wordpress/global-styles-ui'; +import { store as blockEditorStore } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { store as editSiteStore } from '../../store'; +import Revisions from '../revisions'; +import { useGlobalStyles } from './hooks'; + +/** + * Revisions integration - renders conditionally when revisions view is active. + * Coordinates with ScreenRevisions through the path parameter to display + * the currently selected revision. + * + * @param {Object} props Component props. + * @param {string} props.path Current path in global styles. + * @return {JSX.Element|null} The Revisions component or null. + */ +export function GlobalStylesRevisions( { path } ) { + const { editorCanvasContainerView, blocks } = useSelect( ( select ) => { + return { + // This is not ideal: it's like a loop (reading from block-editor to render it). + blocks: select( blockEditorStore ).getBlocks(), + editorCanvasContainerView: unlock( + select( editSiteStore ) + ).getEditorCanvasContainerView(), + }; + }, [] ); + const { user: userConfig } = useGlobalStyles(); + + // Fetch all revisions (includes unsaved, parent, and enriched with authors) + const { revisions, isLoading } = useGlobalStylesRevisions(); + + // Parse revision ID from path (e.g., "/revisions/123" -> "123") + const revisionId = useMemo( () => { + const match = path?.match( /^\/revisions\/(.+)$/ ); + return match ? match[ 1 ] : null; + }, [ path ] ); + + // Find the selected revision from the fetched list + const selectedRevision = useMemo( () => { + if ( ! revisionId || ! revisions.length ) { + return null; + } + return revisions.find( + ( rev ) => String( rev.id ) === String( revisionId ) + ); + }, [ revisionId, revisions ] ); + + // Only render when on the revisions path and the appropriate canvas view is active + const shouldRender = + path?.startsWith( '/revisions' ) && + editorCanvasContainerView === 'global-styles-revisions'; + + if ( ! shouldRender || isLoading ) { + return null; + } + + // Use the selected revision's config if available, otherwise use current user config + const displayConfig = selectedRevision || userConfig; + + return ; +} diff --git a/packages/edit-site/src/components/global-styles/screen-css.js b/packages/edit-site/src/components/global-styles/screen-css.js deleted file mode 100644 index 2fc8fdfecb7a37..00000000000000 --- a/packages/edit-site/src/components/global-styles/screen-css.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { ExternalLink } from '@wordpress/components'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; -import { useDispatch } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; -import { store as editSiteStore } from '../../store'; -import ScreenHeader from './header'; - -const { useGlobalStyle, AdvancedPanel: StylesAdvancedPanel } = unlock( - blockEditorPrivateApis -); - -function ScreenCSS() { - const [ style ] = useGlobalStyle( '', undefined, 'user', { - shouldDecodeEncode: false, - } ); - const [ inheritedStyle, setStyle ] = useGlobalStyle( '', undefined, 'all', { - shouldDecodeEncode: false, - } ); - - const { setEditorCanvasContainerView } = unlock( - useDispatch( editSiteStore ) - ); - - return ( - <> - - { __( - 'You can add custom CSS to further customize the appearance and layout of your site.' - ) } -
- - { __( 'Learn more about CSS' ) } - - - } - onBack={ () => { - setEditorCanvasContainerView( undefined ); - } } - /> -
- -
- - ); -} - -export default ScreenCSS; diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/index.js b/packages/edit-site/src/components/global-styles/screen-revisions/index.js deleted file mode 100644 index 7c5b0f54c8e6d6..00000000000000 --- a/packages/edit-site/src/components/global-styles/screen-revisions/index.js +++ /dev/null @@ -1,202 +0,0 @@ -/** - * WordPress dependencies - */ -import { __, sprintf } from '@wordpress/i18n'; -import { - __experimentalConfirmDialog as ConfirmDialog, - Spinner, -} from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { useContext, useState, useEffect } from '@wordpress/element'; -import { - privateApis as blockEditorPrivateApis, - store as blockEditorStore, -} from '@wordpress/block-editor'; - -/** - * Internal dependencies - */ -import ScreenHeader from '../header'; -import { unlock } from '../../../lock-unlock'; -import Revisions from '../../revisions'; -import { store as editSiteStore } from '../../../store'; -import useGlobalStylesRevisions from './use-global-styles-revisions'; -import RevisionsButtons from './revisions-buttons'; -import StyleBook from '../../style-book'; -import Pagination from '../../pagination'; - -const { GlobalStylesContext, areGlobalStyleConfigsEqual } = unlock( - blockEditorPrivateApis -); - -const PAGE_SIZE = 10; - -function ScreenRevisions() { - const { user: currentEditorGlobalStyles, setUserConfig } = - useContext( GlobalStylesContext ); - const { blocks, editorCanvasContainerView } = useSelect( - ( select ) => ( { - editorCanvasContainerView: unlock( - select( editSiteStore ) - ).getEditorCanvasContainerView(), - blocks: select( blockEditorStore ).getBlocks(), - } ), - [] - ); - const [ currentPage, setCurrentPage ] = useState( 1 ); - const [ currentRevisions, setCurrentRevisions ] = useState( [] ); - const { revisions, isLoading, hasUnsavedChanges, revisionsCount } = - useGlobalStylesRevisions( { - query: { - per_page: PAGE_SIZE, - page: currentPage, - }, - } ); - - const numPages = Math.ceil( revisionsCount / PAGE_SIZE ); - - const [ currentlySelectedRevision, setCurrentlySelectedRevision ] = - useState( currentEditorGlobalStyles ); - const [ - isLoadingRevisionWithUnsavedChanges, - setIsLoadingRevisionWithUnsavedChanges, - ] = useState( false ); - const { setEditorCanvasContainerView } = unlock( - useDispatch( editSiteStore ) - ); - const selectedRevisionMatchesEditorStyles = areGlobalStyleConfigsEqual( - currentlySelectedRevision, - currentEditorGlobalStyles - ); - - // The actual code that triggers the revisions screen to navigate back - // to the home screen in in `packages/edit-site/src/components/global-styles/ui.js`. - const onCloseRevisions = () => { - const canvasContainerView = - editorCanvasContainerView === 'global-styles-revisions:style-book' - ? 'style-book' - : undefined; - setEditorCanvasContainerView( canvasContainerView ); - }; - - const restoreRevision = ( revision ) => { - setUserConfig( () => revision ); - setIsLoadingRevisionWithUnsavedChanges( false ); - onCloseRevisions(); - }; - - useEffect( () => { - if ( ! isLoading && revisions.length ) { - setCurrentRevisions( revisions ); - } - }, [ revisions, isLoading ] ); - - const firstRevision = revisions[ 0 ]; - const currentlySelectedRevisionId = currentlySelectedRevision?.id; - const shouldSelectFirstItem = - !! firstRevision?.id && - ! selectedRevisionMatchesEditorStyles && - ! currentlySelectedRevisionId; - - useEffect( () => { - /* - * Ensure that the first item is selected and loaded into the preview pane - * when no revision is selected and the selected styles don't match the current editor styles. - * This is required in case editor styles are changed outside the revisions panel, - * e.g., via the reset styles function of useGlobalStylesReset(). - * See: https://github.com/WordPress/gutenberg/issues/55866 - */ - if ( shouldSelectFirstItem ) { - setCurrentlySelectedRevision( firstRevision ); - } - }, [ shouldSelectFirstItem, firstRevision ] ); - - // Only display load button if there is a revision to load, - // and it is different from the current editor styles. - const isLoadButtonEnabled = - !! currentlySelectedRevisionId && - currentlySelectedRevisionId !== 'unsaved' && - ! selectedRevisionMatchesEditorStyles; - const hasRevisions = !! currentRevisions.length; - - return ( - <> - - { ! hasRevisions && ( - - ) } - { hasRevisions && - ( editorCanvasContainerView === - 'global-styles-revisions:style-book' ? ( - {} } - onClose={ () => { - setEditorCanvasContainerView( - 'global-styles-revisions' - ); - } } - /> - ) : ( - - ) ) } - - hasUnsavedChanges - ? setIsLoadingRevisionWithUnsavedChanges( true ) - : restoreRevision( currentlySelectedRevision ) - } - /> - { numPages > 1 && ( -
- -
- ) } - { isLoadingRevisionWithUnsavedChanges && ( - - restoreRevision( currentlySelectedRevision ) - } - onCancel={ () => - setIsLoadingRevisionWithUnsavedChanges( false ) - } - size="medium" - > - { __( - 'Are you sure you want to apply this revision? Any unsaved changes will be lost.' - ) } - - ) } - - ); -} - -export default ScreenRevisions; diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/test/use-global-styles-revisions.js b/packages/edit-site/src/components/global-styles/screen-revisions/test/use-global-styles-revisions.js deleted file mode 100644 index 0262086e58b2ad..00000000000000 --- a/packages/edit-site/src/components/global-styles/screen-revisions/test/use-global-styles-revisions.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * External dependencies - */ -import { renderHook } from '@testing-library/react'; - -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import useGlobalStylesRevisions from '../use-global-styles-revisions'; - -jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() ); - -jest.mock( '@wordpress/element', () => { - return { - __esModule: true, - ...jest.requireActual( '@wordpress/element' ), - useContext: jest.fn().mockImplementation( () => ( { - user: { - styles: 'ice-cream', - settings: 'cake', - }, - } ) ), - }; -} ); - -describe( 'useGlobalStylesRevisions', () => { - const selectValue = { - authors: [ - { - id: 4, - name: 'sam', - }, - ], - currentUser: { - name: 'fred', - avatar_urls: {}, - }, - isDirty: false, - revisions: [ - { - id: 1, - author: 4, - settings: {}, - styles: {}, - }, - ], - isLoadingGlobalStylesRevisions: false, - revisionsCount: 1, - }; - - it( 'returns loaded revisions with no unsaved changes', () => { - useSelect.mockImplementation( () => selectValue ); - - const { result } = renderHook( () => useGlobalStylesRevisions() ); - const { revisions, isLoading, hasUnsavedChanges } = result.current; - - expect( isLoading ).toBe( false ); - expect( hasUnsavedChanges ).toBe( false ); - expect( revisions ).toEqual( [ - { - author: { - id: 4, - name: 'sam', - }, - id: 1, - isLatest: true, - settings: {}, - styles: {}, - }, - { - id: 'parent', - settings: {}, - styles: {}, - }, - ] ); - } ); - - it( 'returns loaded revisions with saved changes', () => { - useSelect.mockImplementation( () => ( { - ...selectValue, - isDirty: true, - } ) ); - - const { result } = renderHook( () => useGlobalStylesRevisions() ); - const { revisions, isLoading, hasUnsavedChanges } = result.current; - - expect( isLoading ).toBe( false ); - expect( hasUnsavedChanges ).toBe( true ); - expect( revisions ).toEqual( [ - { - author: { - avatar_urls: {}, - name: 'fred', - }, - id: 'unsaved', - modified: revisions[ 0 ].modified, - settings: 'cake', - styles: 'ice-cream', - }, - { - author: { - id: 4, - name: 'sam', - }, - id: 1, - isLatest: true, - settings: {}, - styles: {}, - }, - { - id: 'parent', - settings: {}, - styles: {}, - }, - ] ); - } ); - - it( 'returns empty revisions', () => { - useSelect.mockImplementation( () => ( { - ...selectValue, - revisions: [], - } ) ); - - const { result } = renderHook( () => useGlobalStylesRevisions() ); - const { revisions, isLoading, hasUnsavedChanges } = result.current; - - expect( isLoading ).toBe( false ); - expect( hasUnsavedChanges ).toBe( false ); - expect( revisions ).toEqual( [] ); - } ); - - it( 'returns loading status when resolving global revisions', () => { - useSelect.mockImplementation( () => ( { - ...selectValue, - isLoadingGlobalStylesRevisions: true, - } ) ); - - const { result } = renderHook( () => useGlobalStylesRevisions() ); - const { isLoading } = result.current; - - expect( isLoading ).toBe( true ); - } ); - - it( 'returns empty revisions when authors are not yet available', () => { - useSelect.mockImplementation( () => ( { - ...selectValue, - authors: [], - } ) ); - - const { result } = renderHook( () => useGlobalStylesRevisions() ); - const { revisions, isLoading, hasUnsavedChanges } = result.current; - - expect( isLoading ).toBe( true ); - expect( hasUnsavedChanges ).toBe( false ); - expect( revisions ).toEqual( [] ); - } ); - - it( 'should prepend unsaved changes item and append reset item to paginated results', () => { - useSelect.mockImplementation( () => ( { - ...selectValue, - revisionsCount: 2, - isDirty: true, - } ) ); - - // Prepend unsaved changes item to paginated results. - const { result: resultPrepend } = renderHook( () => - useGlobalStylesRevisions( { - query: { - per_page: 1, - page: 1, - }, - } ) - ); - expect( resultPrepend.current.revisions ).toEqual( [ - { - author: { - avatar_urls: {}, - name: 'fred', - }, - id: 'unsaved', - modified: resultPrepend.current.revisions[ 0 ].modified, - settings: 'cake', - styles: 'ice-cream', - }, - { - author: { - id: 4, - name: 'sam', - }, - id: 1, - isLatest: true, - settings: {}, - styles: {}, - }, - ] ); - - // Append reset item to paginated results. - const { result: resultAppend } = renderHook( () => - useGlobalStylesRevisions( { - query: { - per_page: 1, - page: 2, - }, - } ) - ); - expect( resultAppend.current.revisions ).toEqual( [ - { - author: { - id: 4, - name: 'sam', - }, - id: 1, - settings: {}, - styles: {}, - }, - { - id: 'parent', - settings: {}, - styles: {}, - }, - ] ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/screen-style-variations.js b/packages/edit-site/src/components/global-styles/screen-style-variations.js deleted file mode 100644 index a3feecd347c7a3..00000000000000 --- a/packages/edit-site/src/components/global-styles/screen-style-variations.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * WordPress dependencies - */ -import { - privateApis as blockEditorPrivateApis, - store as blockEditorStore, -} from '@wordpress/block-editor'; -import { Card, CardBody } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; - -/** - * Internal dependencies - */ -import ScreenHeader from './header'; -import SidebarNavigationScreenGlobalStylesContent from '../sidebar-navigation-screen-global-styles/content'; -import { unlock } from '../../lock-unlock'; - -const { useZoomOut } = unlock( blockEditorPrivateApis ); - -function ScreenStyleVariations() { - // Style Variations should only be previewed in with - // - a "zoomed out" editor (but not when in preview mode) - // - "Desktop" device preview - const isPreviewMode = useSelect( ( select ) => { - return select( blockEditorStore ).getSettings().isPreviewMode; - }, [] ); - useZoomOut( ! isPreviewMode ); - - return ( - <> - - - - - - - - - ); -} - -export default ScreenStyleVariations; diff --git a/packages/edit-site/src/components/global-styles/style-book-integration.js b/packages/edit-site/src/components/global-styles/style-book-integration.js new file mode 100644 index 00000000000000..7a9e873805d505 --- /dev/null +++ b/packages/edit-site/src/components/global-styles/style-book-integration.js @@ -0,0 +1,68 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { store as editSiteStore } from '../../store'; +import StyleBook from '../style-book'; +import { STYLE_BOOK_COLOR_GROUPS } from '../style-book/constants'; + +/** + * Style Book integration - renders conditionally when style book is active. + * + * @param {Object} props Component props. + * @param {string} props.path Current path in the style book. + * @param {Function} props.onPathChange Callback when the path changes. + * @return {JSX.Element|null} The Style Book component or null. + */ +export function GlobalStylesStyleBook( { path, onPathChange } ) { + const editorCanvasContainerView = useSelect( + ( select ) => + unlock( select( editSiteStore ) ).getEditorCanvasContainerView(), + [] + ); + + if ( + editorCanvasContainerView !== 'style-book' && + editorCanvasContainerView !== 'global-styles-revisions:style-book' + ) { + return null; + } + + return ( + + // Match '/blocks/core%2Fbutton' and + // '/blocks/core%2Fbutton/typography', but not + // '/blocks/core%2Fbuttons'. + path === `/blocks/${ encodeURIComponent( blockName ) }` || + path?.startsWith( + `/blocks/${ encodeURIComponent( blockName ) }/` + ) + } + onSelect={ ( blockName ) => { + if ( + STYLE_BOOK_COLOR_GROUPS.find( + ( group ) => group.slug === blockName + ) + ) { + // Go to color palettes Global Styles. + onPathChange?.( '/colors/palette' ); + return; + } + if ( blockName === 'typography' ) { + // Go to typography Global Styles. + onPathChange?.( '/typography' ); + return; + } + + // Now go to the selected block. + onPathChange?.( '/blocks/' + encodeURIComponent( blockName ) ); + } } + /> + ); +} diff --git a/packages/edit-site/src/components/global-styles/style.scss b/packages/edit-site/src/components/global-styles/style.scss index c0efc5cd9858e8..6cdaa63512918a 100644 --- a/packages/edit-site/src/components/global-styles/style.scss +++ b/packages/edit-site/src/components/global-styles/style.scss @@ -1,265 +1,11 @@ @use "@wordpress/base-styles/colors" as *; @use "@wordpress/base-styles/variables" as *; -.edit-site-global-styles-preview { - display: flex; - align-items: center; - justify-content: center; - line-height: 1; - cursor: pointer; -} - -.edit-site-global-styles-preview__wrapper { - max-width: 100%; - display: block; - width: 100%; -} - -.edit-site-typography-preview { - display: flex; - align-items: center; - justify-content: center; - min-height: 100px; - margin-bottom: $grid-unit-20; - background: $gray-100; - border-radius: $radius-small; - overflow: hidden; -} - -.edit-site-font-size__item { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - line-break: anywhere; -} - -.edit-site-font-size__item-value { - color: $gray-700; -} - -.edit-site-global-styles-screen { - margin: $grid-unit-15 $grid-unit-20 $grid-unit-20; -} - -.edit-site-global-styles-screen-typography__indicator { - height: 24px; - width: 24px; - font-size: 14px; - display: flex !important; - align-items: center; - justify-content: center; - border-radius: $radius-x-small; -} - -.edit-site-global-styles-screen-typography__font-variants-count { - color: $gray-700; -} - -.edit-site-global-styles-font-families__manage-fonts { - justify-content: center; -} - -.edit-site-global-styles-screen .color-block-support-panel { - padding-left: 0; - padding-right: 0; - padding-top: 0; - border-top: none; - row-gap: calc(#{$grid-unit-05} * 3); -} - .edit-site-global-styles-header__description { padding: 0 $grid-unit-20; } -.edit-site-block-types-search { - margin-bottom: $grid-unit-10; - padding: 0 $grid-unit-20; -} - .edit-site-global-styles-header { // Need to override the too specific bottom margin for complementary areas. margin-bottom: 0 !important; } - -.edit-site-global-styles-subtitle { - // Need to override the too specific styles for complementary areas. - margin-bottom: 0 !important; - text-transform: uppercase; - font-weight: $font-weight-medium !important; - font-size: 11px !important; -} - -.edit-site-global-styles-section-title { - color: $gray-800; - font-weight: 600; - line-height: 1.2; - padding: $grid-unit-20 $grid-unit-20 0; - margin: 0; -} - -.edit-site-global-styles-icon-with-current-color { - fill: currentColor; -} - -.edit-site-global-styles__color-indicator-wrapper { - // Match the height of the rest of the icons (24px). - height: $grid-unit * 3; - flex-shrink: 0; -} - -.edit-site-global-styles__shadows-panel__options-container, -.edit-site-global-styles__typography-panel__options-container { - height: $grid-unit * 3; -} - -.edit-site-global-styles__block-preview-panel { - position: relative; - width: 100%; - border: $gray-200 $border-width solid; - border-radius: $radius-medium; - overflow: hidden; -} - -.edit-site-global-styles__shadow-preview-panel { - height: $grid-unit-60 * 3; - border: $gray-200 $border-width solid; - border-radius: $radius-medium; - overflow: auto; - background-image: repeating-linear-gradient(45deg, #f5f5f5 25%, #0000 0, #0000 75%, #f5f5f5 0, #f5f5f5), repeating-linear-gradient(45deg, #f5f5f5 25%, #0000 0, #0000 75%, #f5f5f5 0, #f5f5f5); - background-position: 0 0, 8px 8px; - background-size: 16px 16px; - - .edit-site-global-styles__shadow-preview-block { - border: $gray-200 $border-width solid; - border-radius: $radius-small; - background-color: $white; - width: 60%; - height: 60px; - } -} - -.edit-site-global-styles__shadow-editor__dropdown-content { - width: 280px; -} - -.edit-site-global-styles__shadow-editor-panel { - // because tooltip of the range control is too close to the edge and creates overflow - margin-bottom: $grid-unit-05; -} - -.edit-site-global-styles__shadow-editor__dropdown { - width: 100%; - position: relative; -} - -.edit-site-global-styles__shadow-editor__dropdown-toggle { - width: 100%; - height: auto; - padding-top: $grid-unit; - padding-bottom: $grid-unit; - text-align: left; - border-radius: inherit; - - &.is-open { - background: $gray-100; - color: var(--wp-admin-theme-color); - } -} - -.edit-site-global-styles__shadow-editor__remove-button { - position: absolute; - right: $grid-unit; - top: $grid-unit; - opacity: 0; - - &.edit-site-global-styles__shadow-editor__remove-button { - border: none; - } - - .edit-site-global-styles__shadow-editor__dropdown-toggle:hover + &, - &:focus, - &:hover { - opacity: 1; - } - - @media (hover: none) { - // Show reset button on devices that do not support hover. - opacity: 1; - } -} - -.edit-site-global-styles-screen-css { - flex: 1 1 auto; - display: flex; - flex-direction: column; - margin: $grid-unit-20; - - .components-v-stack { - flex: 1 1 auto; - - .block-editor-global-styles-advanced-panel__custom-css-input { - flex: 1 1 auto; - display: flex; - flex-direction: column; - - .components-base-control__field { - flex: 1 1 auto; - display: flex; - flex-direction: column; - - .components-textarea-control__input { - flex: 1 1 auto; - // CSS input is always LTR regardless of language. - /*rtl:ignore*/ - direction: ltr; - } - } - } - } -} - -.edit-site-global-styles-screen-css-help-link { - display: inline-block; - margin-top: $grid-unit-10; -} -.edit-site-global-styles-screen-variations { - margin-top: $grid-unit-20; - border-top: 1px solid $gray-300; - - & > * { - margin: $grid-unit-30 $grid-unit-20; - } -} - -.edit-site-global-styles-sidebar__navigator-provider { - height: 100%; -} - -.edit-site-global-styles-sidebar__navigator-screen { - display: flex; - flex-direction: column; - height: 100%; -} - -.edit-site-global-styles-sidebar__navigator-screen .single-column { - grid-column: span 1; -} - -.edit-site-global-styles-screen-root.edit-site-global-styles-screen-root, -.edit-site-global-styles-screen-style-variations.edit-site-global-styles-screen-style-variations { - background: unset; - color: inherit; -} - -.edit-site-global-styles-sidebar__panel .block-editor-block-icon svg { - fill: currentColor; -} - -.edit-site-global-styles-screen-root__active-style-tile { - // Todo: revisit use of Card component and/or remove override - // The &#{&} is a workaround for the specificity of the Card component. - &#{&}, - &#{&} .edit-site-global-styles-screen-root__active-style-tile-preview { - border-radius: $radius-small; - } -} diff --git a/packages/edit-site/src/components/global-styles/subtitle.js b/packages/edit-site/src/components/global-styles/subtitle.js deleted file mode 100644 index 3a8e7ed9cd6f01..00000000000000 --- a/packages/edit-site/src/components/global-styles/subtitle.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * WordPress dependencies - */ -import { __experimentalHeading as Heading } from '@wordpress/components'; - -function Subtitle( { children, level } ) { - return ( - - { children } - - ); -} - -export default Subtitle; diff --git a/packages/edit-site/src/components/global-styles/typeset.js b/packages/edit-site/src/components/global-styles/typeset.js deleted file mode 100644 index e99e6a037500ad..00000000000000 --- a/packages/edit-site/src/components/global-styles/typeset.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - __experimentalItemGroup as ItemGroup, - __experimentalVStack as VStack, - __experimentalHStack as HStack, -} from '@wordpress/components'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; -import { privateApis as editorPrivateApis } from '@wordpress/editor'; -import { useContext } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import FontLibraryProvider, { - FontLibraryContext, -} from './font-library-modal/context'; -import FontLibraryModal from './font-library-modal'; -import FontFamilyItem from './font-family-item'; -import Subtitle from './subtitle'; -import { getFontFamilies } from './utils'; -import { unlock } from '../../lock-unlock'; - -const { GlobalStylesContext } = unlock( blockEditorPrivateApis ); -const { mergeBaseAndUserConfigs } = unlock( editorPrivateApis ); - -function Typesets() { - const { modalTabOpen, setModalTabOpen } = useContext( FontLibraryContext ); - const { base } = useContext( GlobalStylesContext ); - const { user: userConfig } = useContext( GlobalStylesContext ); - const config = mergeBaseAndUserConfigs( base, userConfig ); - const allFontFamilies = getFontFamilies( config ); - const hasFonts = - allFontFamilies.filter( ( font ) => font !== null ).length > 0; - - return ( - hasFonts && ( - <> - { !! modalTabOpen && ( - setModalTabOpen( null ) } - defaultTabId={ modalTabOpen } - /> - ) } - - - - { __( 'Fonts' ) } - - - { allFontFamilies.map( - ( font ) => - font && ( - - ) - ) } - - - - ) - ); -} - -export default ( { ...props } ) => ( - - - -); diff --git a/packages/edit-site/src/components/global-styles/typography-preview.js b/packages/edit-site/src/components/global-styles/typography-preview.js deleted file mode 100644 index 092f4e4e3b05e9..00000000000000 --- a/packages/edit-site/src/components/global-styles/typography-preview.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * WordPress dependencies - */ -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; - -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; - -const { useGlobalStyle } = unlock( blockEditorPrivateApis ); - -export default function TypographyPreview( { name, element, headingLevel } ) { - let prefix = ''; - if ( element === 'heading' ) { - prefix = `elements.${ headingLevel }.`; - } else if ( element && element !== 'text' ) { - prefix = `elements.${ element }.`; - } - - const [ fontFamily ] = useGlobalStyle( - prefix + 'typography.fontFamily', - name - ); - const [ gradientValue ] = useGlobalStyle( prefix + 'color.gradient', name ); - const [ backgroundColor ] = useGlobalStyle( - prefix + 'color.background', - name - ); - const [ fallbackBackgroundColor ] = useGlobalStyle( 'color.background' ); - const [ color ] = useGlobalStyle( prefix + 'color.text', name ); - const [ fontSize ] = useGlobalStyle( prefix + 'typography.fontSize', name ); - const [ fontStyle ] = useGlobalStyle( - prefix + 'typography.fontStyle', - name - ); - const [ fontWeight ] = useGlobalStyle( - prefix + 'typography.fontWeight', - name - ); - const [ letterSpacing ] = useGlobalStyle( - prefix + 'typography.letterSpacing', - name - ); - const extraStyles = - element === 'link' - ? { - textDecoration: 'underline', - } - : {}; - - return ( -
- Aa -
- ); -} diff --git a/packages/edit-site/src/components/global-styles/ui.js b/packages/edit-site/src/components/global-styles/ui.js deleted file mode 100644 index 22ebad383884e9..00000000000000 --- a/packages/edit-site/src/components/global-styles/ui.js +++ /dev/null @@ -1,448 +0,0 @@ -/** - * WordPress dependencies - */ -import { - Navigator, - useNavigator, - createSlotFill, - DropdownMenu, - MenuGroup, - MenuItem, -} from '@wordpress/components'; -import { getBlockTypes, store as blocksStore } from '@wordpress/blocks'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { - privateApis as blockEditorPrivateApis, - store as blockEditorStore, -} from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; -import { store as preferencesStore } from '@wordpress/preferences'; -import { moreVertical } from '@wordpress/icons'; -import { store as coreStore } from '@wordpress/core-data'; -import { useEffect } from '@wordpress/element'; -import { usePrevious } from '@wordpress/compose'; - -/** - * Internal dependencies - */ -import ScreenRoot from './screen-root'; -import { - useBlockHasGlobalStyles, - default as ScreenBlockList, -} from './screen-block-list'; -import ScreenBlock from './screen-block'; -import ScreenTypography from './screen-typography'; -import ScreenTypographyElement from './screen-typography-element'; -import FontSize from './font-sizes/font-size'; -import FontSizes from './font-sizes/font-sizes'; -import ScreenColors from './screen-colors'; -import ScreenColorPalette from './screen-color-palette'; -import ScreenBackground from './screen-background'; -import { ScreenShadows, ScreenShadowsEdit } from './screen-shadows'; -import ScreenLayout from './screen-layout'; -import ScreenStyleVariations from './screen-style-variations'; -import StyleBook from '../style-book'; -import ScreenCSS from './screen-css'; -import ScreenRevisions from './screen-revisions'; -import { unlock } from '../../lock-unlock'; -import { store as editSiteStore } from '../../store'; -import { STYLE_BOOK_COLOR_GROUPS } from '../style-book/constants'; - -const SLOT_FILL_NAME = 'GlobalStylesMenu'; -const { useGlobalStylesReset } = unlock( blockEditorPrivateApis ); -const { Slot: GlobalStylesMenuSlot, Fill: GlobalStylesMenuFill } = - createSlotFill( SLOT_FILL_NAME ); - -function GlobalStylesActionMenu() { - const [ canReset, onReset ] = useGlobalStylesReset(); - const { toggle } = useDispatch( preferencesStore ); - const { canEditCSS } = useSelect( ( select ) => { - const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = - select( coreStore ); - - const globalStylesId = __experimentalGetCurrentGlobalStylesId(); - const globalStyles = globalStylesId - ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) - : undefined; - - return { - canEditCSS: !! globalStyles?._links?.[ 'wp:action-edit-css' ], - }; - }, [] ); - const { setEditorCanvasContainerView } = unlock( - useDispatch( editSiteStore ) - ); - const loadCustomCSS = () => { - setEditorCanvasContainerView( 'global-styles-css' ); - }; - - return ( - - - { ( { onClose } ) => ( - <> - - { canEditCSS && ( - - { __( 'Additional CSS' ) } - - ) } - { - toggle( - 'core/edit-site', - 'welcomeGuideStyles' - ); - onClose(); - } } - > - { __( 'Welcome Guide' ) } - - - - { - onReset(); - onClose(); - } } - disabled={ ! canReset } - > - { __( 'Reset styles' ) } - - - - ) } - - - ); -} - -function GlobalStylesNavigationScreen( { className, ...props } ) { - return ( - - ); -} - -function BlockStylesNavigationScreens( { - parentMenu, - blockStyles, - blockName, -} ) { - return blockStyles.map( ( style, index ) => ( - - - - ) ); -} - -function ContextScreens( { name, parentMenu = '' } ) { - const blockStyleVariations = useSelect( - ( select ) => { - const { getBlockStyles } = select( blocksStore ); - return getBlockStyles( name ); - }, - [ name ] - ); - - return ( - <> - - - - - { !! blockStyleVariations?.length && ( - - ) } - - ); -} - -function GlobalStylesStyleBook() { - const navigator = useNavigator(); - const { path } = navigator.location; - return ( - - // Match '/blocks/core%2Fbutton' and - // '/blocks/core%2Fbutton/typography', but not - // '/blocks/core%2Fbuttons'. - path === `/blocks/${ encodeURIComponent( blockName ) }` || - path.startsWith( - `/blocks/${ encodeURIComponent( blockName ) }/` - ) - } - onSelect={ ( blockName ) => { - if ( - STYLE_BOOK_COLOR_GROUPS.find( - ( group ) => group.slug === blockName - ) - ) { - // Go to color palettes Global Styles. - navigator.goTo( '/colors/palette' ); - return; - } - if ( blockName === 'typography' ) { - // Go to typography Global Styles. - navigator.goTo( '/typography' ); - return; - } - - // Now go to the selected block. - navigator.goTo( '/blocks/' + encodeURIComponent( blockName ) ); - } } - /> - ); -} - -function GlobalStylesBlockLink() { - const navigator = useNavigator(); - const { selectedBlockName, selectedBlockClientId } = useSelect( - ( select ) => { - const { getSelectedBlockClientId, getBlockName } = - select( blockEditorStore ); - const clientId = getSelectedBlockClientId(); - return { - selectedBlockName: getBlockName( clientId ), - selectedBlockClientId: clientId, - }; - }, - [] - ); - const blockHasGlobalStyles = useBlockHasGlobalStyles( selectedBlockName ); - // When we're in the `Blocks` screen enable deep linking to the selected block. - useEffect( () => { - if ( ! selectedBlockClientId || ! blockHasGlobalStyles ) { - return; - } - const currentPath = navigator.location.path; - if ( - currentPath !== '/blocks' && - ! currentPath.startsWith( '/blocks/' ) - ) { - return; - } - const newPath = '/blocks/' + encodeURIComponent( selectedBlockName ); - // Avoid navigating to the same path. This can happen when selecting - // a new block of the same type. - if ( newPath !== currentPath ) { - navigator.goTo( newPath, { skipFocus: true } ); - } - }, [ selectedBlockClientId, selectedBlockName, blockHasGlobalStyles ] ); -} - -function GlobalStylesEditorCanvasContainerLink() { - const { goTo, location } = useNavigator(); - const editorCanvasContainerView = useSelect( - ( select ) => - unlock( select( editSiteStore ) ).getEditorCanvasContainerView(), - [] - ); - const path = location?.path; - const isRevisionsOpen = path === '/revisions'; - - // If the user switches the editor canvas container view, redirect - // to the appropriate screen. This effectively allows deep linking to the - // desired screens from outside the global styles navigation provider. - useEffect( () => { - switch ( editorCanvasContainerView ) { - case 'global-styles-revisions': - case 'global-styles-revisions:style-book': - if ( ! isRevisionsOpen ) { - goTo( '/revisions' ); - } - break; - case 'global-styles-css': - goTo( '/css' ); - break; - // The stand-alone style book is open - // and the revisions panel is open, - // close the revisions panel. - // Otherwise keep the style book open while - // browsing global styles panel. - // - // Falling through as it matches the default scenario. - case 'style-book': - default: - // In general, if the revision screen is in view but the - // `editorCanvasContainerView` is not a revision view, close it. - // This also includes the scenario when the stand-alone style - // book is open, in which case we want the user to close the - // revisions screen and browse global styles. - if ( isRevisionsOpen ) { - goTo( '/', { isBack: true } ); - } - break; - } - }, [ editorCanvasContainerView, isRevisionsOpen, goTo ] ); -} - -function useNavigatorSync( parentPath, onPathChange ) { - const navigator = useNavigator(); - const { path: childPath } = navigator.location; - const previousParentPath = usePrevious( parentPath ); - const previousChildPath = usePrevious( childPath ); - useEffect( () => { - if ( parentPath !== childPath ) { - if ( parentPath !== previousParentPath ) { - navigator.goTo( parentPath ); - } else if ( childPath !== previousChildPath ) { - onPathChange( childPath ); - } - } - }, [ - onPathChange, - parentPath, - previousChildPath, - previousParentPath, - childPath, - navigator, - ] ); -} - -// This component is used to wrap the hook in order to conditionally execute it -// when the parent component is used on controlled mode. -function NavigationSync( { path: parentPath, onPathChange, children } ) { - useNavigatorSync( parentPath, onPathChange ); - return children; -} - -function GlobalStylesUI( { path, onPathChange } ) { - const blocks = getBlockTypes(); - const editorCanvasContainerView = useSelect( - ( select ) => - unlock( select( editSiteStore ) ).getEditorCanvasContainerView(), - [] - ); - - return ( - - { path && onPathChange && ( - - ) } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { blocks.map( ( block ) => ( - - - - ) ) } - - - - { blocks.map( ( block ) => ( - - ) ) } - - { 'style-book' === editorCanvasContainerView && ( - - ) } - - - - - - ); -} -export { GlobalStylesMenuSlot }; -export default GlobalStylesUI; diff --git a/packages/edit-site/src/components/global-styles/utils.js b/packages/edit-site/src/components/global-styles/utils.js deleted file mode 100644 index 66a25854a06fe1..00000000000000 --- a/packages/edit-site/src/components/global-styles/utils.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * - * @param {string} variation The variation name. - * - * @return {string} The variation class name. - */ -export function getVariationClassName( variation ) { - if ( ! variation ) { - return ''; - } - return `is-style-${ variation }`; -} - -/** - * Iterates through the presets array and searches for slugs that start with the specified - * slugPrefix followed by a numerical suffix. It identifies the highest numerical suffix found - * and returns one greater than the highest found suffix, ensuring that the new index is unique. - * - * @param {Array} presets The array of preset objects, each potentially containing a slug property. - * @param {string} slugPrefix The prefix to look for in the preset slugs. - * - * @return {number} The next available index for a preset with the specified slug prefix, or 1 if no matching slugs are found. - */ -export function getNewIndexFromPresets( presets, slugPrefix ) { - const nameRegex = new RegExp( `^${ slugPrefix }([\\d]+)$` ); - const highestPresetValue = presets.reduce( ( currentHighest, preset ) => { - if ( typeof preset?.slug === 'string' ) { - const matches = preset?.slug.match( nameRegex ); - if ( matches ) { - const id = parseInt( matches[ 1 ], 10 ); - if ( id > currentHighest ) { - return id; - } - } - } - return currentHighest; - }, 0 ); - return highestPresetValue + 1; -} - -function getFontFamilyFromSetting( fontFamilies, setting ) { - if ( ! Array.isArray( fontFamilies ) || ! setting ) { - return null; - } - - const fontFamilyVariable = setting.replace( 'var(', '' ).replace( ')', '' ); - const fontFamilySlug = fontFamilyVariable?.split( '--' ).slice( -1 )[ 0 ]; - - return fontFamilies.find( - ( fontFamily ) => fontFamily.slug === fontFamilySlug - ); -} - -export function getFontFamilies( themeJson ) { - const themeFontFamilies = - themeJson?.settings?.typography?.fontFamilies?.theme; - const customFontFamilies = - themeJson?.settings?.typography?.fontFamilies?.custom; - - let fontFamilies = []; - if ( themeFontFamilies && customFontFamilies ) { - fontFamilies = [ ...themeFontFamilies, ...customFontFamilies ]; - } else if ( themeFontFamilies ) { - fontFamilies = themeFontFamilies; - } else if ( customFontFamilies ) { - fontFamilies = customFontFamilies; - } - const bodyFontFamilySetting = themeJson?.styles?.typography?.fontFamily; - const bodyFontFamily = getFontFamilyFromSetting( - fontFamilies, - bodyFontFamilySetting - ); - - const headingFontFamilySetting = - themeJson?.styles?.elements?.heading?.typography?.fontFamily; - - let headingFontFamily; - if ( ! headingFontFamilySetting ) { - headingFontFamily = bodyFontFamily; - } else { - headingFontFamily = getFontFamilyFromSetting( - fontFamilies, - themeJson?.styles?.elements?.heading?.typography?.fontFamily - ); - } - - return [ bodyFontFamily, headingFontFamily ]; -} diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js index 6acb5a2dfddf48..c23169acb87015 100644 --- a/packages/edit-site/src/components/layout/index.js +++ b/packages/edit-site/src/components/layout/index.js @@ -21,12 +21,10 @@ import { } from '@wordpress/compose'; import { __, sprintf } from '@wordpress/i18n'; import { useState, useRef, useEffect } from '@wordpress/element'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { EditorSnackbars, UnsavedChangesWarning, ErrorBoundary, - privateApis as editorPrivateApis, } from '@wordpress/editor'; import { privateApis as routerPrivateApis } from '@wordpress/router'; import { PluginArea } from '@wordpress/plugins'; @@ -46,9 +44,8 @@ import useMovingAnimation from './animation'; import { SidebarContent, SidebarNavigationProvider } from '../sidebar'; import SaveHub from '../save-hub'; import SavePanel from '../save-panel'; +import { useStyle } from '../global-styles'; -const { useGlobalStyle } = unlock( blockEditorPrivateApis ); -const { GlobalStylesProvider } = unlock( editorPrivateApis ); const { useLocation } = unlock( routerPrivateApis ); const ANIMATION_DURATION = 0.3; @@ -77,8 +74,8 @@ function Layout() { }; } ); - const [ backgroundColor ] = useGlobalStyle( 'color.background' ); - const [ gradientValue ] = useGlobalStyle( 'color.gradient' ); + const backgroundColor = useStyle( 'color.background' ); + const gradientValue = useStyle( 'color.gradient' ); const previousCanvaMode = usePrevious( canvas ); useEffect( () => { if ( previousCanvaMode === 'edit' ) { @@ -276,11 +273,9 @@ export default function LayoutWithGlobalStylesProvider( props ) { return ( - - { /** This needs to be within the SlotFillProvider */ } - - - + { /** This needs to be within the SlotFillProvider */ } + + ); } diff --git a/packages/edit-site/src/components/page-patterns/fields.js b/packages/edit-site/src/components/page-patterns/fields.js index d884508e575068..dfbf7a85e4b2e2 100644 --- a/packages/edit-site/src/components/page-patterns/fields.js +++ b/packages/edit-site/src/components/page-patterns/fields.js @@ -9,10 +9,7 @@ import clsx from 'clsx'; import { __experimentalHStack as HStack } from '@wordpress/components'; import { __, _x } from '@wordpress/i18n'; import { useState, useMemo, useId } from '@wordpress/element'; -import { - BlockPreview, - privateApis as blockEditorPrivateApis, -} from '@wordpress/block-editor'; +import { BlockPreview } from '@wordpress/block-editor'; import { Icon } from '@wordpress/icons'; import { parse } from '@wordpress/blocks'; @@ -24,16 +21,14 @@ import { PATTERN_SYNC_TYPES, OPERATOR_IS, } from '../../utils/constants'; -import { unlock } from '../../lock-unlock'; import { useAddedBy } from '../page-templates/hooks'; - -const { useGlobalStyle } = unlock( blockEditorPrivateApis ); +import { useStyle } from '../global-styles'; function PreviewField( { item } ) { const descriptionId = useId(); const description = item.description || item?.excerpt?.raw; const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE; - const [ backgroundColor ] = useGlobalStyle( 'color.background' ); + const backgroundColor = useStyle( 'color.background' ); const blocks = useMemo( () => { return ( item.blocks ?? diff --git a/packages/edit-site/src/components/page-templates/fields.js b/packages/edit-site/src/components/page-templates/fields.js index 9bbed2bf9d933c..3fde1679b54ddd 100644 --- a/packages/edit-site/src/components/page-templates/fields.js +++ b/packages/edit-site/src/components/page-templates/fields.js @@ -15,10 +15,7 @@ import { __, _x } from '@wordpress/i18n'; import { useState, useMemo } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; import { parse } from '@wordpress/blocks'; -import { - BlockPreview, - privateApis as blockEditorPrivateApis, -} from '@wordpress/block-editor'; +import { BlockPreview } from '@wordpress/block-editor'; import { EditorProvider } from '@wordpress/editor'; import { privateApis as corePrivateApis, @@ -33,8 +30,8 @@ import { useAddedBy } from './hooks'; import { useDefaultTemplateTypes } from '../add-new-template/utils'; import usePatternSettings from '../page-patterns/use-pattern-settings'; import { unlock } from '../../lock-unlock'; +import { useStyle } from '../global-styles'; -const { useGlobalStyle } = unlock( blockEditorPrivateApis ); const { Badge } = unlock( componentsPrivateApis ); const { useEntityRecordsWithPermissions } = unlock( corePrivateApis ); @@ -61,7 +58,7 @@ function useAllDefaultTemplateTypes() { function PreviewField( { item } ) { const settings = usePatternSettings(); - const [ backgroundColor = 'white' ] = useGlobalStyle( 'color.background' ); + const backgroundColor = useStyle( 'color.background' ) ?? 'white'; const blocks = useMemo( () => { return parse( item.content.raw ); }, [ item.content.raw ] ); diff --git a/packages/edit-site/src/components/revisions/index.js b/packages/edit-site/src/components/revisions/index.js index 528ec6c2647390..91295a8777b267 100644 --- a/packages/edit-site/src/components/revisions/index.js +++ b/packages/edit-site/src/components/revisions/index.js @@ -10,9 +10,9 @@ import { __unstableEditorStyles as EditorStyles, __unstableIframe as Iframe, } from '@wordpress/block-editor'; -import { privateApis as editorPrivateApis } from '@wordpress/editor'; import { useSelect } from '@wordpress/data'; -import { useContext, useMemo } from '@wordpress/element'; +import { useMemo } from '@wordpress/element'; +import { mergeGlobalStyles } from '@wordpress/global-styles-engine'; /** * Internal dependencies @@ -21,24 +21,23 @@ import { useContext, useMemo } from '@wordpress/element'; import { unlock } from '../../lock-unlock'; import EditorCanvasContainer from '../editor-canvas-container'; import { useGlobalStylesOutputWithConfig } from '../../hooks/use-global-styles-output'; +import { useGlobalStyles } from '../global-styles'; const { ExperimentalBlockEditorProvider, - GlobalStylesContext, __unstableBlockStyleVariationOverridesWithConfig, } = unlock( blockEditorPrivateApis ); -const { mergeBaseAndUserConfigs } = unlock( editorPrivateApis ); function isObjectEmpty( object ) { return ! object || Object.keys( object ).length === 0; } function Revisions( { userConfig, blocks } ) { - const { base: baseConfig } = useContext( GlobalStylesContext ); + const { base: baseConfig } = useGlobalStyles(); const mergedConfig = useMemo( () => { if ( ! isObjectEmpty( userConfig ) && ! isObjectEmpty( baseConfig ) ) { - return mergeBaseAndUserConfigs( baseConfig, userConfig ); + return mergeGlobalStyles( baseConfig, userConfig ); } return {}; }, [ baseConfig, userConfig ] ); diff --git a/packages/edit-site/src/components/sidebar-global-styles-wrapper/index.js b/packages/edit-site/src/components/sidebar-global-styles-wrapper/index.js index 4565bcd243e359..2bbd64f431c024 100644 --- a/packages/edit-site/src/components/sidebar-global-styles-wrapper/index.js +++ b/packages/edit-site/src/components/sidebar-global-styles-wrapper/index.js @@ -3,25 +3,18 @@ */ import { Page } from '@wordpress/admin-ui'; import { __ } from '@wordpress/i18n'; -import { useSelect } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; import { useMemo, useState } from '@wordpress/element'; import { privateApis as routerPrivateApis } from '@wordpress/router'; import { useViewportMatch } from '@wordpress/compose'; -import { - Button, - __experimentalHStack as HStack, - DropdownMenu, - MenuGroup, - MenuItem, -} from '@wordpress/components'; +import { Button, __experimentalHStack as HStack } from '@wordpress/components'; import { addQueryArgs, removeQueryArgs } from '@wordpress/url'; -import { seen, moreVertical } from '@wordpress/icons'; +import { seen } from '@wordpress/icons'; /** * Internal dependencies */ -import GlobalStylesUI from '../global-styles/ui'; +import GlobalStylesUI from '../global-styles'; +import { GlobalStylesActionMenu } from '../global-styles/menu'; import { unlock } from '../../lock-unlock'; const { useLocation, useHistory } = unlock( routerPrivateApis ); @@ -32,15 +25,6 @@ const GlobalStylesPageActions = ( { path, } ) => { const history = useHistory(); - const canEditCSS = useSelect( ( select ) => { - const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = - select( coreStore ); - const globalStylesId = __experimentalGetCurrentGlobalStylesId(); - const globalStyles = globalStylesId - ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) - : undefined; - return !! globalStyles?._links?.[ 'wp:action-edit-css' ]; - }, [] ); return ( @@ -58,32 +42,7 @@ const GlobalStylesPageActions = ( { } } size="compact" /> - { canEditCSS && ( - - { ( { onClose } ) => ( - - { canEditCSS && ( - { - onClose(); - history.navigate( - addQueryArgs( path, { - section: '/css', - } ) - ); - } } - > - { __( 'Additional CSS' ) } - - ) } - - ) } - - ) } + ); }; diff --git a/packages/edit-site/src/components/sidebar-global-styles-wrapper/style.scss b/packages/edit-site/src/components/sidebar-global-styles-wrapper/style.scss index c54af3006a646a..cdd5c3ae2ad06a 100644 --- a/packages/edit-site/src/components/sidebar-global-styles-wrapper/style.scss +++ b/packages/edit-site/src/components/sidebar-global-styles-wrapper/style.scss @@ -2,13 +2,13 @@ @use "@wordpress/base-styles/variables" as *; .edit-site-styles { - .edit-site-global-styles-screen-root { + .global-styles-ui-screen-root { box-shadow: none; & > div > hr { display: none; } } - .edit-site-global-styles-sidebar__navigator-provider { + .global-styles-ui-sidebar__navigator-provider { .components-tools-panel { border-top: none; } @@ -16,7 +16,7 @@ padding-left: 0; padding-right: 0; - .edit-site-global-styles-sidebar__navigator-screen { + .global-styles-ui-sidebar__navigator-screen { padding-top: $grid-unit-15; padding-left: $grid-unit-15; padding-right: $grid-unit-15; diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/content.js b/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/content.js index ce8cd32aa009c5..7982e5cf3246ad 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/content.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/content.js @@ -3,25 +3,50 @@ */ import { __ } from '@wordpress/i18n'; import { __experimentalVStack as VStack } from '@wordpress/components'; +import { + StyleVariations, + ColorVariations, + TypographyVariations, +} from '@wordpress/global-styles-ui'; /** * Internal dependencies */ -import StyleVariationsContainer from '../global-styles/style-variations-container'; -import ColorVariations from '../global-styles/variations/variations-color'; -import TypographyVariations from '../global-styles/variations/variations-typography'; +import { useGlobalStyles } from '../global-styles'; export default function SidebarNavigationScreenGlobalStylesContent() { const gap = 3; + const { + user: userConfig, + base: baseConfig, + setUser: setUserConfig, + } = useGlobalStyles(); return ( - - - + + + ); } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/index.js index a5902dc37362c5..5be6a889459bf8 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-global-styles/index.js @@ -15,7 +15,7 @@ import SidebarNavigationScreen from '../sidebar-navigation-screen'; import { unlock } from '../../lock-unlock'; import { store as editSiteStore } from '../../store'; import SidebarNavigationItem from '../sidebar-navigation-item'; -import useGlobalStylesRevisions from '../global-styles/screen-revisions/use-global-styles-revisions'; +import { useGlobalStylesRevisions } from '@wordpress/global-styles-ui'; import SidebarNavigationScreenDetailsFooter from '../sidebar-navigation-screen-details-footer'; import { MainSidebarNavigationContent } from '../sidebar-navigation-screen-main'; diff --git a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss index 25c809647d8cae..8650b0fc02f5ee 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss @@ -72,29 +72,22 @@ } } -.edit-site-global-styles-variation-title { - color: $gray-300; - font-size: 11px; - text-transform: uppercase; - font-weight: $font-weight-medium; -} - -.edit-site-sidebar-navigation-screen__content .edit-site-global-styles-variations_item { +.edit-site-sidebar-navigation-screen__content .global-styles-ui-variations_item { // Use a white outline to provide contrast with the dark background. - .edit-site-global-styles-variations_item-preview { + .global-styles-ui-variations_item-preview { outline-color: rgba($white, 0.05); } - &:not(.is-active):hover .edit-site-global-styles-variations_item-preview { + &:not(.is-active):hover .global-styles-ui-variations_item-preview { outline-color: rgba($white, 0.15); } - &.is-active .edit-site-global-styles-variations_item-preview { + &.is-active .global-styles-ui-variations_item-preview { outline-color: $white; } - &:focus-visible .edit-site-global-styles-variations_item-preview { + &:focus-visible .global-styles-ui-variations_item-preview { outline-color: var(--wp-admin-theme-color); } } diff --git a/packages/edit-site/src/components/style-book/index.js b/packages/edit-site/src/components/style-book/index.js index 63bd2b697c6c1e..199defd534df0e 100644 --- a/packages/edit-site/src/components/style-book/index.js +++ b/packages/edit-site/src/components/style-book/index.js @@ -22,13 +22,12 @@ import { __unstableIframe as Iframe, __experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients, } from '@wordpress/block-editor'; -import { privateApis as editorPrivateApis } from '@wordpress/editor'; import { useSelect, dispatch } from '@wordpress/data'; +import { mergeGlobalStyles } from '@wordpress/global-styles-engine'; import { useMemo, useState, memo, - useContext, useRef, useLayoutEffect, useEffect, @@ -51,17 +50,14 @@ import { getExamples } from './examples'; import { store as siteEditorStore } from '../../store'; import { useSection } from '../sidebar-global-styles-wrapper'; import { GlobalStylesRenderer } from '../global-styles-renderer'; -import { getVariationClassName } from '../global-styles/utils'; import { STYLE_BOOK_COLOR_GROUPS, STYLE_BOOK_PREVIEW_CATEGORIES, } from '../style-book/constants'; import { useGlobalStylesOutputWithConfig } from '../../hooks/use-global-styles-output'; +import { useStyle, useGlobalStyles } from '../global-styles'; -const { ExperimentalBlockEditorProvider, useGlobalStyle, GlobalStylesContext } = - unlock( blockEditorPrivateApis ); -const { mergeBaseAndUserConfigs } = unlock( editorPrivateApis ); - +const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); const { Tabs } = unlock( componentsPrivateApis ); function isObjectEmpty( object ) { @@ -234,7 +230,7 @@ function applyBlockVariationsToExamples( examples, variation ) { attributes: { ...block.attributes, style: undefined, - className: getVariationClassName( variation ), + className: `is-style-${ variation }`, }, } ) ) : { @@ -242,7 +238,7 @@ function applyBlockVariationsToExamples( examples, variation ) { attributes: { ...example.blocks.attributes, style: undefined, - className: getVariationClassName( variation ), + className: `is-style-${ variation }`, }, }, }; @@ -260,8 +256,8 @@ function StyleBook( { userConfig = {}, path = '', } ) { - const [ textColor ] = useGlobalStyle( 'color.text' ); - const [ backgroundColor ] = useGlobalStyle( 'color.background' ); + const textColor = useStyle( 'color.text' ); + const backgroundColor = useStyle( 'color.background' ); const colors = useMultiOriginPalettes(); const examples = useMemo( () => getExamples( colors ), [ colors ] ); const tabs = useMemo( @@ -276,12 +272,12 @@ function StyleBook( { const examplesForSinglePageUse = getExamplesForSinglePageUse( examples ); - const { base: baseConfig } = useContext( GlobalStylesContext ); + const { base: baseConfig } = useGlobalStyles(); const goTo = getStyleBookNavigationFromPath( path ); const mergedConfig = useMemo( () => { if ( ! isObjectEmpty( userConfig ) && ! isObjectEmpty( baseConfig ) ) { - return mergeBaseAndUserConfigs( baseConfig, userConfig ); + return mergeGlobalStyles( baseConfig, userConfig ); } return {}; }, [ baseConfig, userConfig ] ); @@ -522,12 +518,12 @@ export const StyleBookPreview = ( { userConfig = {}, isStatic = false } ) => { filteredExamples, ] ); - const { base: baseConfig } = useContext( GlobalStylesContext ); + const { base: baseConfig } = useGlobalStyles(); const goTo = getStyleBookNavigationFromPath( section ); const mergedConfig = useMemo( () => { if ( ! isObjectEmpty( userConfig ) && ! isObjectEmpty( baseConfig ) ) { - return mergeBaseAndUserConfigs( baseConfig, userConfig ); + return mergeGlobalStyles( baseConfig, userConfig ); } return {}; }, [ baseConfig, userConfig ] ); diff --git a/packages/edit-site/src/hooks/commands/use-common-commands.js b/packages/edit-site/src/hooks/commands/use-common-commands.js index 1d43cc9b3bf20a..39839f1a5c5b89 100644 --- a/packages/edit-site/src/hooks/commands/use-common-commands.js +++ b/packages/edit-site/src/hooks/commands/use-common-commands.js @@ -6,7 +6,6 @@ import { useDispatch, useSelect } from '@wordpress/data'; import { __, isRTL } from '@wordpress/i18n'; import { rotateLeft, rotateRight, help, backup } from '@wordpress/icons'; import { useCommandLoader } from '@wordpress/commands'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { privateApis as routerPrivateApis } from '@wordpress/router'; import { store as preferencesStore } from '@wordpress/preferences'; import { store as coreStore } from '@wordpress/core-data'; @@ -16,8 +15,8 @@ import { store as coreStore } from '@wordpress/core-data'; */ import { unlock } from '../../lock-unlock'; import { store as editSiteStore } from '../../store'; +import { useGlobalStyles } from '../../components/global-styles/hooks'; -const { useGlobalStylesReset } = unlock( blockEditorPrivateApis ); const { useHistory, useLocation } = unlock( routerPrivateApis ); const getGlobalStylesToggleWelcomeGuideCommands = () => @@ -69,7 +68,14 @@ const getGlobalStylesToggleWelcomeGuideCommands = () => const getGlobalStylesResetCommands = () => function useGlobalStylesResetCommands() { - const [ canReset, onReset ] = useGlobalStylesReset(); + const { user, setUser } = useGlobalStyles(); + + // Check if there are user customizations that can be reset + const canReset = + !! user && + ( Object.keys( user?.styles ?? {} ).length > 0 || + Object.keys( user?.settings ?? {} ).length > 0 ); + const commands = useMemo( () => { if ( ! canReset ) { return []; @@ -82,11 +88,11 @@ const getGlobalStylesResetCommands = () => icon: isRTL() ? rotateRight : rotateLeft, callback: ( { close } ) => { close(); - onReset(); + setUser( { styles: {}, settings: {} } ); }, }, ]; - }, [ canReset, onReset ] ); + }, [ canReset, setUser ] ); return { isLoading: false, diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 49613c8b4c2822..fa451d62ed8edc 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -15,8 +15,9 @@ import { __EXPERIMENTAL_STYLE_PROPERTY, getBlockType, hasBlockSupport, + store as blocksStore, } from '@wordpress/blocks'; -import { useContext, useMemo, useCallback } from '@wordpress/element'; +import { useMemo, useCallback } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; @@ -24,13 +25,11 @@ import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ -import { useSupportedStyles } from '../../components/global-styles/hooks'; import { unlock } from '../../lock-unlock'; import setNestedValue from '../../utils/set-nested-value'; +import { useGlobalStyles } from '../../components/global-styles'; -const { cleanEmptyObject, GlobalStylesContext } = unlock( - blockEditorPrivateApis -); +const { cleanEmptyObject } = unlock( blockEditorPrivateApis ); // Block Gap is a special case and isn't defined within the blocks // style properties config. We'll add it here to allow it to be pushed @@ -166,7 +165,12 @@ function getFallbackBorderStyleChange( side, border, globalBorderStyle ) { } function useChangesToPush( name, attributes, userConfig ) { - const supports = useSupportedStyles( name ); + const supports = useSelect( + ( select ) => { + return unlock( select( blocksStore ) ).getSupportedStyles( name ); + }, + [ name ] + ); const blockUserConfig = userConfig?.styles?.blocks?.[ name ]; return useMemo( () => { @@ -241,8 +245,7 @@ function PushChangesToGlobalStylesControl( { attributes, setAttributes, } ) { - const { user: userConfig, setUserConfig } = - useContext( GlobalStylesContext ); + const { user: userConfig, setUser: setUserConfig } = useGlobalStyles(); const changes = useChangesToPush( name, attributes, userConfig ); diff --git a/packages/edit-site/src/hooks/use-global-styles-output.js b/packages/edit-site/src/hooks/use-global-styles-output.js index 6033c9b4954b5a..1412358a451e79 100644 --- a/packages/edit-site/src/hooks/use-global-styles-output.js +++ b/packages/edit-site/src/hooks/use-global-styles-output.js @@ -3,19 +3,14 @@ */ import { getBlockTypes, store as blocksStore } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; -import { useContext, useMemo } from '@wordpress/element'; +import { useMemo } from '@wordpress/element'; import { generateGlobalStyles } from '@wordpress/global-styles-engine'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; /** * Internal dependencies */ import { store as editSiteStore } from '../store'; -import { unlock } from '../lock-unlock'; - -const { GlobalStylesContext, useGlobalSetting } = unlock( - blockEditorPrivateApis -); +import { useSetting, useGlobalStyles } from '../components/global-styles'; /** * Returns the global styles output based on the provided global styles config. @@ -29,7 +24,7 @@ export function useGlobalStylesOutputWithConfig( mergedConfig = {}, disableRootPadding = false ) { - const [ blockGap ] = useGlobalSetting( 'spacing.blockGap' ); + const blockGap = useSetting( 'spacing.blockGap' ); const hasBlockGapSupport = blockGap !== null; const hasFallbackGapSupport = ! hasBlockGapSupport; @@ -75,6 +70,6 @@ export function useGlobalStylesOutputWithConfig( * @return {Array} Array of stylesheets and settings. */ export function useGlobalStylesOutput( disableRootPadding = false ) { - const { merged: mergedConfig } = useContext( GlobalStylesContext ); + const { merged: mergedConfig } = useGlobalStyles(); return useGlobalStylesOutputWithConfig( mergedConfig, disableRootPadding ); } diff --git a/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js b/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js index adf98b0d89b019..182beb9e75e679 100644 --- a/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js +++ b/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js @@ -3,21 +3,19 @@ */ import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; -import { useContext, useMemo } from '@wordpress/element'; +import { useMemo } from '@wordpress/element'; import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; -import { privateApis as editorPrivateApis } from '@wordpress/editor'; import { __ } from '@wordpress/i18n'; +import { mergeGlobalStyles } from '@wordpress/global-styles-engine'; /** * Internal dependencies */ import { unlock } from '../../lock-unlock'; +import { useGlobalStyles } from '../../components/global-styles'; const EMPTY_ARRAY = []; -const { GlobalStylesContext, areGlobalStyleConfigsEqual } = unlock( - blockEditorPrivateApis -); -const { mergeBaseAndUserConfigs } = unlock( editorPrivateApis ); +const { areGlobalStyleConfigsEqual } = unlock( blockEditorPrivateApis ); /** * Removes all instances of properties from an object. @@ -86,7 +84,7 @@ export function useCurrentMergeThemeStyleVariationsWithUserConfig( variationsFromTheme: _variationsFromTheme || EMPTY_ARRAY, }; }, [] ); - const { user: userVariation } = useContext( GlobalStylesContext ); + const { user: userVariation } = useGlobalStyles(); const propertiesAsString = properties.toString(); @@ -105,7 +103,7 @@ export function useCurrentMergeThemeStyleVariationsWithUserConfig( return isVariationWithProperties( variation, properties ); } ) .map( ( variation ) => { - return mergeBaseAndUserConfigs( + return mergeGlobalStyles( userVariationWithoutProperties, variation ); diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index b8d6acd1c0be0e..ed6acf36aae082 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -4,11 +4,11 @@ @use "@wordpress/admin-ui/build-style/style.css" as admin-ui; @use "@wordpress/dataviews/build-style/style.css" as dataviews; @use "@wordpress/fields/build-style/style.css" as fields; +@use "@wordpress/global-styles-ui/build-style/style.css" as global-styles-ui; @use "./components/add-new-template/style.scss" as *; @use "./components/block-editor/style.scss" as *; @use "./components/canvas-loader/style.scss" as *; @use "./components/global-styles/style.scss" as *; -@use "./components/global-styles/screen-revisions/style.scss" as *; @use "./components/global-styles-sidebar/style.scss" as *; @use "./components/page-patterns/style.scss" as *; @use "./components/page-templates/style.scss" as *; @@ -36,9 +36,7 @@ @use "./components/post-list/style.scss" as *; @use "./components/resizable-frame/style.scss" as *; @use "./hooks/push-changes-to-global-styles/style.scss" as *; -@use "./components/global-styles/font-library-modal/style.scss" as *; @use "./components/pagination/style.scss" as *; -@use "./components/global-styles/variations/style.scss" as *; @use "./components/sidebar-global-styles-wrapper/style.scss" as *; /* stylelint-disable -- Disable reason: View Transitions not supported properly by stylelint. */ diff --git a/packages/edit-site/tsconfig.json b/packages/edit-site/tsconfig.json index 7337f59269286c..5d59e86d63d868 100644 --- a/packages/edit-site/tsconfig.json +++ b/packages/edit-site/tsconfig.json @@ -22,6 +22,7 @@ { "path": "../escape-html" }, { "path": "../fields" }, { "path": "../global-styles-engine" }, + { "path": "../global-styles-ui" }, { "path": "../hooks" }, { "path": "../html-entities" }, { "path": "../i18n" }, diff --git a/packages/editor/package.json b/packages/editor/package.json index 8608e16bede103..009c7315000c6b 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -70,6 +70,7 @@ "@wordpress/dom": "file:../dom", "@wordpress/element": "file:../element", "@wordpress/fields": "file:../fields", + "@wordpress/global-styles-engine": "file:../global-styles-engine", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", @@ -93,9 +94,7 @@ "client-zip": "^2.4.5", "clsx": "^2.1.1", "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", "fast-deep-equal": "^3.1.3", - "is-plain-object": "^5.0.0", "memize": "^2.1.0", "react-autosize-textarea": "^7.1.0", "remove-accents": "^0.5.0", diff --git a/packages/editor/src/components/global-styles-provider/index.js b/packages/editor/src/components/global-styles-provider/index.js index 74fbed5f000624..3b1dee27045050 100644 --- a/packages/editor/src/components/global-styles-provider/index.js +++ b/packages/editor/src/components/global-styles-provider/index.js @@ -1,9 +1,3 @@ -/** - * External dependencies - */ -import deepmerge from 'deepmerge'; -import { isPlainObject } from 'is-plain-object'; - /** * WordPress dependencies */ @@ -11,37 +5,14 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { store as coreStore } from '@wordpress/core-data'; import { useSelect, useDispatch } from '@wordpress/data'; import { useMemo, useCallback } from '@wordpress/element'; +import { mergeGlobalStyles } from '@wordpress/global-styles-engine'; /** * Internal dependencies */ import { unlock } from '../../lock-unlock'; -const { GlobalStylesContext, cleanEmptyObject } = unlock( - blockEditorPrivateApis -); - -export function mergeBaseAndUserConfigs( base, user ) { - return deepmerge( base, user, { - /* - * We only pass as arrays the presets, - * in which case we want the new array of values - * to override the old array (no merging). - */ - isMergeableObject: isPlainObject, - /* - * Exceptions to the above rule. - * Background images should be replaced, not merged, - * as they themselves are specific object definitions for the style. - */ - customMerge: ( key ) => { - if ( key === 'backgroundImage' ) { - return ( baseConfig, userConfig ) => userConfig; - } - return undefined; - }, - } ); -} +const { cleanEmptyObject } = unlock( blockEditorPrivateApis ); function useGlobalStylesUserConfig() { const { globalStylesId, isReady, settings, styles, _links } = useSelect( @@ -212,7 +183,7 @@ export function useGlobalStylesContext() { return {}; } - return mergeBaseAndUserConfigs( baseConfig, userConfig ); + return mergeGlobalStyles( baseConfig, userConfig ); }, [ userConfig, baseConfig ] ); const context = useMemo( () => { @@ -234,16 +205,3 @@ export function useGlobalStylesContext() { return context; } - -export function GlobalStylesProvider( { children } ) { - const context = useGlobalStylesContext(); - if ( ! context.isReady ) { - return null; - } - - return ( - - { children } - - ); -} diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index e064c73b0ae639..857c79fca67913 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -19,10 +19,6 @@ import usePostFields from './components/post-fields'; import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group'; import ViewMoreMenuGroup from './components/more-menu/view-more-menu-group'; import ResizableEditor from './components/resizable-editor'; -import { - mergeBaseAndUserConfigs, - GlobalStylesProvider, -} from './components/global-styles-provider'; import { CreateTemplatePartModal, patternTitleField, @@ -42,8 +38,6 @@ lock( privateApis, { EntitiesSavedStatesExtensible, Editor, EditorContentSlotFill, - GlobalStylesProvider, - mergeBaseAndUserConfigs, PluginPostExcerpt, PostCardPanel, PreferencesModal, diff --git a/packages/editor/tsconfig.json b/packages/editor/tsconfig.json index 00a8f3860e2925..7784405fc6ac10 100644 --- a/packages/editor/tsconfig.json +++ b/packages/editor/tsconfig.json @@ -19,6 +19,7 @@ { "path": "../dom" }, { "path": "../element" }, { "path": "../fields" }, + { "path": "../global-styles-engine" }, { "path": "../hooks" }, { "path": "../html-entities" }, { "path": "../i18n" }, diff --git a/packages/global-styles-ui/README.md b/packages/global-styles-ui/README.md new file mode 100644 index 00000000000000..01da3c70c8d77c --- /dev/null +++ b/packages/global-styles-ui/README.md @@ -0,0 +1,48 @@ +# Global Styles UI + +UI components for managing WordPress Global Styles. + +## Installation + +Install the module: + +```bash +npm install @wordpress/global-styles-ui --save +``` + +## Usage + +```js +import { GlobalStylesUI } from '@wordpress/global-styles-ui'; + +function MyComponent() { + return ( + + ); +} +``` + +## API + +### GlobalStylesUI + +Main component for the Global Styles editor interface. + +**Props:** + +- `value` (GlobalStylesConfig): User's custom global styles +- `baseValue` (GlobalStylesConfig): Theme's default global styles +- `onChange` (Function): Callback when styles change +- `path` (string, optional): Current navigation path +- `onPathChange` (Function, optional): Callback when path changes +- `fontLibraryEnabled` (boolean, optional): Enable font library features +- `serverCSS` (array, optional): Server CSS styles +- `serverSettings` (object, optional): Server settings + +## Contributing + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for details. diff --git a/packages/global-styles-ui/package.json b/packages/global-styles-ui/package.json new file mode 100644 index 00000000000000..a040e3935acac6 --- /dev/null +++ b/packages/global-styles-ui/package.json @@ -0,0 +1,67 @@ +{ + "name": "@wordpress/global-styles-ui", + "version": "1.0.0", + "description": "Global Styles UI components for WordPress.", + "author": "The WordPress Contributors", + "license": "GPL-2.0-or-later", + "keywords": [ + "wordpress", + "gutenberg", + "global-styles", + "design-system" + ], + "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/global-styles-ui/README.md", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/gutenberg.git", + "directory": "packages/global-styles-ui" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "main": "build/index.js", + "module": "build-module/index.js", + "exports": { + ".": { + "types": "./build-types/index.d.ts", + "import": "./build-module/index.js", + "default": "./build/index.js" + }, + "./package.json": "./package.json", + "./build-style/": "./build-style/" + }, + "react-native": "src/index", + "dependencies": { + "@wordpress/a11y": "file:../a11y", + "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/block-editor": "file:../block-editor", + "@wordpress/blocks": "file:../blocks", + "@wordpress/components": "file:../components", + "@wordpress/compose": "file:../compose", + "@wordpress/core-data": "file:../core-data", + "@wordpress/data": "file:../data", + "@wordpress/date": "file:../date", + "@wordpress/element": "file:../element", + "@wordpress/global-styles-engine": "file:../global-styles-engine", + "@wordpress/i18n": "file:../i18n", + "@wordpress/icons": "file:../icons", + "@wordpress/keycodes": "file:../keycodes", + "@wordpress/private-apis": "file:../private-apis", + "change-case": "^4.1.2", + "classnames": "^2.3.2", + "clsx": "^2.1.0", + "colord": "^2.7.0", + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/global-styles-ui/src/README.md b/packages/global-styles-ui/src/README.md new file mode 100644 index 00000000000000..e3877cda103c1e --- /dev/null +++ b/packages/global-styles-ui/src/README.md @@ -0,0 +1,99 @@ +# Global Styles UI + +React component for editing global styles with a familiar interface inspired by WordPress Gutenberg. + +## Public API + +### GlobalStylesUI + +The main component for rendering a global styles editing interface. + +```typescript +import { GlobalStylesUI } from '@wordpress/global-styles-ui'; + + resetStyles()} + onExportCSS={() => exportCSS()} + fontLibraryEnabled={true} + serverCSS={serverCSS} + serverSettings={serverSettings} +/> +``` + +#### Props + +- **`value`** (`GlobalStylesConfig`): The user global styles object (what gets edited) +- **`inheritedValue`** (`GlobalStylesConfig`): The merged global styles object (base + user, for display/inheritance) +- **`onChange`** (`(newValue: GlobalStylesConfig) => void`): Callback when styles change +- **`path`** (`string`, optional): Current navigation path (e.g., "/colors", "/typography") +- **`onPathChange`** (`(newPath: string) => void`, optional): Callback when navigation changes +- **`onReset`** (`() => void`, optional): Callback for reset action +- **`onExportCSS`** (`() => void`, optional): Callback for CSS export action +- **`fontLibraryEnabled`** (`boolean`, optional): Whether font library is enabled (default: false) +- **`serverCSS`** (`{ isGlobalStyles?: boolean }[]`, optional): Server CSS styles for BlockEditorProvider +- **`serverSettings`** (`{ __unstableResolvedAssets: Record }`, optional): Server settings for BlockEditorProvider + +## Dependencies + +This component has the following external dependencies: + +### WordPress Dependencies + +- **`@wordpress/core-data`** - Used internally for fetching: + + - Style variations (`useEntityRecords('root', 'globalStyles')`) + - Font collections and families (`useEntityRecords('postType', 'wp_font_family')`) + - User capabilities (`useSelect(select => select('core').canUser(...))`) + +- **`@wordpress/components`** - UI components (Navigator, Button, Panel, etc.) +- **`@wordpress/blocks`** - Block type information and supports +- **`@wordpress/element`** - React utilities +- **`@wordpress/i18n`** - Internationalization + +### Internal Dependencies + +- **`../global-styles-engine`** - Generic global styles utilities (framework-agnostic) + +## Architecture + +### Internal Structure + +The component is internally generic and framework-agnostic, with WordPress dependencies only used for: + +1. **Data Fetching**: Font collections, style variations, and user capabilities +2. **UI Components**: WordPress design system components +3. **Block Information**: Block type support detection + +### Data Flow + +1. Parent provides `value` (global styles) and `onChange` callback +2. Component uses WordPress stores for additional data (fonts, variations, capabilities) +3. Internal context manages state and provides hooks to child components +4. Changes flow back through `onChange` callback + +## Usage Example + +```typescript +function MyStylesPage() { + const [globalStyles, setGlobalStyles] = useState(initialStyles); + const [currentPath, setCurrentPath] = useState('/'); + + return ( + setGlobalStyles(defaultStyles)} + onExportCSS={() => downloadCSS(globalStyles)} + /> + ); +} +``` + +This component provides a complete global styles editing experience while maintaining a clean, controlled API. diff --git a/packages/edit-site/src/components/global-styles/background-panel.js b/packages/global-styles-ui/src/background-panel.tsx similarity index 57% rename from packages/edit-site/src/components/global-styles/background-panel.js rename to packages/global-styles-ui/src/background-panel.tsx index e185079d8cee04..42c7ca9bf260c2 100644 --- a/packages/edit-site/src/components/global-styles/background-panel.js +++ b/packages/global-styles-ui/src/background-panel.tsx @@ -1,32 +1,32 @@ /** * WordPress dependencies */ +// @ts-expect-error: Not typed yet. import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; /** * Internal dependencies */ -import { unlock } from '../../lock-unlock'; +import { useStyle, useSetting } from './hooks'; +import { unlock } from './lock-unlock'; // Initial control values where no block style is set. const BACKGROUND_DEFAULT_VALUES = { backgroundSize: 'auto', }; -const { - useGlobalStyle, - useGlobalSetting, - BackgroundPanel: StylesBackgroundPanel, -} = unlock( blockEditorPrivateApis ); +const { BackgroundPanel: StylesBackgroundPanel } = unlock( + blockEditorPrivateApis +); /** * Checks if there is a current value in the background image block support * attributes. * - * @param {Object} style Style attribute. - * @return {boolean} Whether the block has a background image value set. + * @param style Style attribute. + * @return Whether the block has a background image value set. */ -export function hasBackgroundImageValue( style ) { +export function hasBackgroundImageValue( style: any ): boolean { return ( !! style?.background?.backgroundImage?.id || !! style?.background?.backgroundImage?.url || @@ -35,13 +35,14 @@ export function hasBackgroundImageValue( style ) { } export default function BackgroundPanel() { - const [ style ] = useGlobalStyle( '', undefined, 'user', { - shouldDecodeEncode: false, - } ); - const [ inheritedStyle, setStyle ] = useGlobalStyle( '', undefined, 'all', { - shouldDecodeEncode: false, - } ); - const [ settings ] = useGlobalSetting( '' ); + const [ style ] = useStyle( '', undefined, 'user', false ); + const [ inheritedStyle, setStyle ] = useStyle( + '', + undefined, + 'merged', + false + ); + const [ settings ] = useSetting( '' ); return ( { +interface BlockPreviewPanelProps { + name: string; + variation?: string; +} + +const BlockPreviewPanel = ( { + name, + variation = '', +}: BlockPreviewPanelProps ) => { const blockExample = getBlockType( name )?.example; const blocks = useMemo( () => { if ( ! blockExample ) { @@ -49,7 +59,7 @@ const BlockPreviewPanel = ( { name, variation = '' } ) => { return (
+ { children } + + ); +} + +export default ColorIndicatorWrapper; diff --git a/packages/edit-site/src/components/global-styles/color-palette-panel.js b/packages/global-styles-ui/src/color-palette-panel.tsx similarity index 67% rename from packages/edit-site/src/components/global-styles/color-palette-panel.js rename to packages/global-styles-ui/src/color-palette-panel.tsx index 606eb996ccccd3..f72c29da219d86 100644 --- a/packages/edit-site/src/components/global-styles/color-palette-panel.js +++ b/packages/global-styles-ui/src/color-palette-panel.tsx @@ -1,6 +1,7 @@ /** * WordPress dependencies */ +import type { Color } from '@wordpress/global-styles-engine'; import { useViewportMatch } from '@wordpress/compose'; import { __experimentalPaletteEdit as PaletteEdit, @@ -8,57 +9,56 @@ import { Button, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { shuffle } from '@wordpress/icons'; /** * Internal dependencies */ -import { unlock } from '../../lock-unlock'; +import { useSetting, useColorRandomizer } from './hooks'; import ColorVariations from './variations/variations-color'; -import { useColorRandomizer } from './hooks'; -const { useGlobalSetting } = unlock( blockEditorPrivateApis ); -const mobilePopoverProps = { placement: 'bottom-start', offset: 8 }; +const mobilePopoverProps = { placement: 'bottom-start' as const, offset: 8 }; -export default function ColorPalettePanel( { name } ) { - const [ themeColors, setThemeColors ] = useGlobalSetting( +interface ColorPalettePanelProps { + name?: string; +} + +export default function ColorPalettePanel( { name }: ColorPalettePanelProps ) { + const [ themeColors, setThemeColors ] = useSetting< Color[] >( 'color.palette.theme', name ); - const [ baseThemeColors ] = useGlobalSetting( + const [ baseThemeColors ] = useSetting< Color[] >( 'color.palette.theme', name, 'base' ); - const [ defaultColors, setDefaultColors ] = useGlobalSetting( + const [ defaultColors, setDefaultColors ] = useSetting< Color[] >( 'color.palette.default', name ); - const [ baseDefaultColors ] = useGlobalSetting( + const [ baseDefaultColors ] = useSetting< Color[] >( 'color.palette.default', name, 'base' ); - const [ customColors, setCustomColors ] = useGlobalSetting( + const [ customColors, setCustomColors ] = useSetting< Color[] >( 'color.palette.custom', name ); - const [ defaultPaletteEnabled ] = useGlobalSetting( + const [ defaultPaletteEnabled ] = useSetting< boolean >( 'color.defaultPalette', name ); + const isMobileViewport = useViewportMatch( 'small', '<' ); const popoverProps = isMobileViewport ? mobilePopoverProps : undefined; - const [ randomizeThemeColors ] = useColorRandomizer(); + const [ randomizeThemeColors ] = useColorRandomizer( name ); return ( - + { !! themeColors && !! themeColors.length && ( ) } - { window.__experimentalEnableColorRandomizer && - themeColors?.length > 0 && ( + { ( window as any ).__experimentalEnableColorRandomizer && + themeColors?.length > 0 && + randomizeThemeColors && (
) } - { ! isLoading && ( + { ! isLoading && selectedCollection && ( <> - - - - - - - { categories && - categories.map( ( category ) => ( - - ) ) } - - - + + + + { categories && + categories.map( ( category ) => ( + + ) ) } + + @@ -400,7 +412,7 @@ function FontCollection( { slug } ) { { selectedFont?.name } @@ -440,29 +452,30 @@ function FontCollection( { slug } ) { role="list" className="font-library-modal__fonts-list" > - { getSortedFontFaces( selectedFont ).map( - ( face, i ) => ( -
  • - -
  • - ) - ) } + { selectedFont && + getSortedFontFaces( selectedFont ).map( + ( face, i ) => ( +
  • + +
  • + ) + ) } { /* eslint-enable jsx-a11y/no-redundant-roles */ } @@ -507,7 +520,7 @@ function FontCollection( { slug } ) { sprintf( // translators: 1: Current page number, 2: Total number of pages. _x( - '
    Page
    %1$s
    of %2$s
    ', + '
    Page
    %1$s
    of %2$d
    ', 'paging' ), '', @@ -520,13 +533,17 @@ function FontCollection( { slug } ) { aria-label={ __( 'Current page' ) } - value={ page } + value={ page.toString() } options={ [ ...Array( totalPages ), ].map( ( e, i ) => { return { - label: i + 1, - value: i + 1, + label: ( + i + 1 + ).toString(), + value: ( + i + 1 + ).toString(), }; } ) } onChange={ ( newPage ) => diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/font-demo.js b/packages/global-styles-ui/src/font-library-modal/font-demo.tsx similarity index 76% rename from packages/edit-site/src/components/global-styles/font-library-modal/font-demo.js rename to packages/global-styles-ui/src/font-library-modal/font-demo.tsx index 0320bdd4e4893f..d371098c9a7287 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/font-demo.js +++ b/packages/global-styles-ui/src/font-library-modal/font-demo.tsx @@ -12,24 +12,29 @@ import { getFacePreviewStyle, getFamilyPreviewStyle, } from './utils/preview-styles'; +import type { FontFamily, FontFace, FontDemoProps } from './types'; -function getPreviewUrl( fontFace ) { +function getPreviewUrl( fontFace: FontFace ): string | undefined { if ( fontFace.preview ) { return fontFace.preview; } if ( fontFace.src ) { return Array.isArray( fontFace.src ) ? fontFace.src[ 0 ] : fontFace.src; } + return undefined; } -function getDisplayFontFace( font ) { +function getDisplayFontFace( font: FontFamily | FontFace ): FontFace { // if this IS a font face return it - if ( font.fontStyle || font.fontWeight ) { + if ( + ( 'fontStyle' in font && font.fontStyle ) || + ( 'fontWeight' in font && font.fontWeight ) + ) { return font; } // if this is a font family with a collection of font faces // return the first one that is normal and 400 OR just the first one - if ( font.fontFace && font.fontFace.length ) { + if ( 'fontFace' in font && font.fontFace && font.fontFace.length ) { return ( font.fontFace.find( ( face ) => @@ -47,16 +52,16 @@ function getDisplayFontFace( font ) { }; } -function FontDemo( { font, text } ) { - const ref = useRef( null ); +function FontDemo( { font, text }: FontDemoProps ) { + const ref = useRef< HTMLDivElement >( null ); const fontFace = getDisplayFontFace( font ); const style = getFamilyPreviewStyle( font ); - text = text || font.name; + text = text || ( 'name' in font ? font.name : '' ); const customPreviewUrl = font.preview; - const [ isIntersecting, setIsIntersecting ] = useState( false ); - const [ isAssetLoaded, setIsAssetLoaded ] = useState( false ); + const [ isIntersecting, setIsIntersecting ] = useState< boolean >( false ); + const [ isAssetLoaded, setIsAssetLoaded ] = useState< boolean >( false ); const { loadFontFaceAsset } = useContext( FontLibraryContext ); const previewUrl = customPreviewUrl ?? getPreviewUrl( fontFace ); @@ -76,7 +81,9 @@ function FontDemo( { font, text } ) { const observer = new window.IntersectionObserver( ( [ entry ] ) => { setIsIntersecting( entry.isIntersecting ); }, {} ); - observer.observe( ref.current ); + if ( ref.current ) { + observer.observe( ref.current ); + } return () => observer.disconnect(); }, [ ref ] ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/google-fonts-confirm-dialog.js b/packages/global-styles-ui/src/font-library-modal/google-fonts-confirm-dialog.tsx similarity index 93% rename from packages/edit-site/src/components/global-styles/font-library-modal/google-fonts-confirm-dialog.js rename to packages/global-styles-ui/src/font-library-modal/google-fonts-confirm-dialog.tsx index 369edc6c9ffb42..ae37027fd6fa97 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/google-fonts-confirm-dialog.js +++ b/packages/global-styles-ui/src/font-library-modal/google-fonts-confirm-dialog.tsx @@ -11,8 +11,8 @@ import { __experimentalSpacer as Spacer, } from '@wordpress/components'; -function GoogleFontsConfirmDialog() { - const handleConfirm = () => { +function GoogleFontsConfirmDialog(): JSX.Element { + const handleConfirm = (): void => { // eslint-disable-next-line no-undef window.localStorage.setItem( 'wp-font-library-google-fonts-permission', diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/index.js b/packages/global-styles-ui/src/font-library-modal/index.tsx similarity index 88% rename from packages/edit-site/src/components/global-styles/font-library-modal/index.js rename to packages/global-styles-ui/src/font-library-modal/index.tsx index 5661a002f71ecb..51d2f630a0660b 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/index.js +++ b/packages/global-styles-ui/src/font-library-modal/index.tsx @@ -17,7 +17,8 @@ import InstalledFonts from './installed-fonts'; import FontCollection from './font-collection'; import UploadFonts from './upload-fonts'; import { FontLibraryContext } from './context'; -import { unlock } from '../../../lock-unlock'; +import type { FontCollection as FontCollectionType } from './types'; +import { unlock } from '../lock-unlock'; const { Tabs } = unlock( componentsPrivateApis ); @@ -31,7 +32,7 @@ const UPLOAD_TAB = { title: _x( 'Upload', 'noun' ), }; -const tabsFromCollections = ( collections ) => +const tabsFromCollections = ( collections: FontCollectionType[] ) => collections.map( ( { slug, name } ) => ( { id: slug, title: @@ -43,6 +44,9 @@ const tabsFromCollections = ( collections ) => function FontLibraryModal( { onRequestClose, defaultTabId = 'installed-fonts', +}: { + onRequestClose: () => void; + defaultTabId?: string; } ) { const { collections } = useContext( FontLibraryContext ); const canUserCreate = useSelect( ( select ) => { @@ -52,7 +56,7 @@ function FontLibraryModal( { } ); }, [] ); - const tabs = [ DEFAULT_TAB ]; + const tabs: { id: string; title: string }[] = [ DEFAULT_TAB ]; if ( canUserCreate ) { tabs.push( UPLOAD_TAB ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js b/packages/global-styles-ui/src/font-library-modal/installed-fonts.tsx similarity index 82% rename from packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js rename to packages/global-styles-ui/src/font-library-modal/installed-fonts.tsx index b7666a66afe0b3..3afc001e50331b 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js +++ b/packages/global-styles-ui/src/font-library-modal/installed-fonts.tsx @@ -21,7 +21,10 @@ import { useSelect } from '@wordpress/data'; import { useContext, useEffect, useState } from '@wordpress/element'; import { __, _x, sprintf, isRTL } from '@wordpress/i18n'; import { chevronLeft, chevronRight } from '@wordpress/icons'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; +import type { + FontFamilyPreset, + GlobalStylesConfig, +} from '@wordpress/global-styles-engine'; /** * Internal dependencies @@ -36,9 +39,8 @@ import { unloadFontFaceInBrowser, getDisplaySrcFromFontFace, } from './utils'; -import { unlock } from '../../../lock-unlock'; - -const { useGlobalSetting } = unlock( blockEditorPrivateApis ); +import { useSetting } from '../hooks'; +import type { FontFamily } from './types'; function InstalledFonts() { const { @@ -53,21 +55,23 @@ function InstalledFonts() { getFontFacesActivated, } = useContext( FontLibraryContext ); - const [ fontFamilies, setFontFamilies ] = useGlobalSetting( - 'typography.fontFamilies' - ); - const [ isConfirmDeleteOpen, setIsConfirmDeleteOpen ] = useState( false ); - const [ notice, setNotice ] = useState( false ); - const [ baseFontFamilies ] = useGlobalSetting( - 'typography.fontFamilies', - undefined, - 'base' - ); + const [ fontFamilies, setFontFamilies ] = useSetting< + Record< string, FontFamilyPreset[] > | undefined + >( 'typography.fontFamilies' ); + const [ isConfirmDeleteOpen, setIsConfirmDeleteOpen ] = + useState< boolean >( false ); + const [ notice, setNotice ] = useState< { + type: 'success' | 'error' | 'info'; + message: string; + } | null >( null ); + const [ baseFontFamilies ] = useSetting< + Record< string, FontFamilyPreset[] > | undefined + >( 'typography.fontFamilies', undefined, 'base' ); const globalStylesId = useSelect( ( select ) => { const { __experimentalGetCurrentGlobalStylesId } = select( coreStore ); return __experimentalGetCurrentGlobalStylesId(); - } ); - const globalStyles = useEntityRecord( + }, [] ); + const globalStyles = useEntityRecord< GlobalStylesConfig >( 'root', 'globalStyles', globalStylesId @@ -131,13 +135,13 @@ function InstalledFonts() { message: sprintf( /* translators: %s: error message */ __( 'There was an error updating the font family. %s' ), - error.message + ( error as Error ).message ), } ); } }; - const getFontFacesToDisplay = ( font ) => { + const getFontFacesToDisplay = ( font: FontFamily ) => { if ( ! font ) { return []; } @@ -153,16 +157,18 @@ function InstalledFonts() { return sortFontFaces( font.fontFace ); }; - const getFontCardVariantsText = ( font ) => { + const getFontCardVariantsText = ( font: FontFamily ) => { const variantsInstalled = - font?.fontFace?.length > 0 ? font.fontFace.length : 1; + font?.fontFace && ( font?.fontFace?.length ?? 0 ) > 0 + ? font.fontFace.length + : 1; const variantsActive = getFontFacesActivated( font.slug, font.source ).length; return sprintf( /* translators: 1: Active font variants, 2: Total font variants. */ - __( '%1$s/%2$s variants active' ), + __( '%1$d/%2$d variants active' ), variantsActive, variantsInstalled ); @@ -194,6 +200,9 @@ function InstalledFonts() { // Toggle select all fonts. const toggleSelectAll = () => { + if ( ! libraryFontSelected || ! libraryFontSelected?.source ) { + return; + } const initialFonts = fontFamilies?.[ libraryFontSelected.source ]?.filter( ( f ) => f.slug !== libraryFontSelected.slug @@ -212,11 +221,12 @@ function InstalledFonts() { if ( isSelectAllChecked ) { unloadFontFaceInBrowser( face, 'all' ); } else { - loadFontFaceInBrowser( - face, - getDisplaySrcFromFontFace( face?.src ), - 'all' + const displaySrc = getDisplaySrcFromFontFace( + face?.src ?? '' ); + if ( displaySrc ) { + loadFontFaceInBrowser( face, displaySrc, 'all' ); + } } } ); } @@ -339,16 +349,18 @@ function InstalledFonts() {
    - + { libraryFontSelected && ( + + ) } { - handleSetLibraryFontSelected( null ); + handleSetLibraryFontSelected( + undefined + ); setNotice( null ); } } label={ __( 'Back' ) } @@ -365,7 +379,7 @@ function InstalledFonts() { { libraryFontSelected?.name } @@ -408,20 +422,21 @@ function InstalledFonts() { role="list" className="font-library-modal__fonts-list" > - { getFontFacesToDisplay( - libraryFontSelected - ).map( ( face, i ) => ( -
  • - ( +
  • -
  • - ) ) } + className="font-library-modal__fonts-list-item" + > + + + ) ) } { /* eslint-enable jsx-a11y/no-redundant-roles */ } @@ -466,6 +481,20 @@ function ConfirmDeleteDialog( { setNotice, uninstallFontFamily, handleSetLibraryFontSelected, +}: { + font: FontFamily; + isOpen: boolean; + setIsOpen: ( isOpen: boolean ) => void; + setNotice: ( + notice: { + type: 'success' | 'error' | 'info'; + message: string; + } | null + ) => void; + uninstallFontFamily: ( + fontFamily: FontFamily + ) => Promise< { deleted: boolean } >; + handleSetLibraryFontSelected: ( font?: FontFamily ) => void; } ) { const navigator = useNavigator(); @@ -475,7 +504,7 @@ function ConfirmDeleteDialog( { try { await uninstallFontFamily( font ); navigator.goBack(); - handleSetLibraryFontSelected( null ); + handleSetLibraryFontSelected( undefined ); setNotice( { type: 'success', message: __( 'Font family uninstalled successfully.' ), @@ -485,7 +514,7 @@ function ConfirmDeleteDialog( { type: 'error', message: __( 'There was an error uninstalling the font family.' ) + - error.message, + ( error as Error ).message, } ); } }; diff --git a/packages/global-styles-ui/src/font-library-modal/lib/inflate.js b/packages/global-styles-ui/src/font-library-modal/lib/inflate.js new file mode 100644 index 00000000000000..a80bc507e0db7b --- /dev/null +++ b/packages/global-styles-ui/src/font-library-modal/lib/inflate.js @@ -0,0 +1,4112 @@ +/** + * Credits: + * + * lib-font + * https://github.com/Pomax/lib-font + * https://github.com/Pomax/lib-font/blob/master/lib/inflate.js + * + * The MIT License (MIT) + * + * Copyright (c) 2020 pomax@nihongoresources.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint eslint-comments/no-unlimited-disable: 0 */ +/* eslint-disable */ +/* pako 1.0.10 nodeca/pako */ ( function ( f ) { + if ( typeof exports === 'object' && typeof module !== 'undefined' ) { + module.exports = f(); + } else if ( typeof define === 'function' && define.amd ) { + define( [], f ); + } else { + var g; + if ( typeof window !== 'undefined' ) { + g = window; + } else if ( typeof global !== 'undefined' ) { + g = global; + } else if ( typeof self !== 'undefined' ) { + g = self; + } else { + g = this; + } + g.pako = f(); + } +} )( function () { + var define, module, exports; + return ( function () { + function r( e, n, t ) { + function o( i, f ) { + if ( ! n[ i ] ) { + if ( ! e[ i ] ) { + var c = 'function' == typeof require && require; + if ( ! f && c ) return c( i, ! 0 ); + if ( u ) return u( i, ! 0 ); + var a = new Error( "Cannot find module '" + i + "'" ); + throw ( ( a.code = 'MODULE_NOT_FOUND' ), a ); + } + var p = ( n[ i ] = { exports: {} } ); + e[ i ][ 0 ].call( + p.exports, + function ( r ) { + var n = e[ i ][ 1 ][ r ]; + return o( n || r ); + }, + p, + p.exports, + r, + e, + n, + t + ); + } + return n[ i ].exports; + } + for ( + var u = 'function' == typeof require && require, i = 0; + i < t.length; + i++ + ) + o( t[ i ] ); + return o; + } + return r; + } )()( + { + 1: [ + function ( require, module, exports ) { + 'use strict'; + + var TYPED_OK = + typeof Uint8Array !== 'undefined' && + typeof Uint16Array !== 'undefined' && + typeof Int32Array !== 'undefined'; + + function _has( obj, key ) { + return Object.prototype.hasOwnProperty.call( obj, key ); + } + + exports.assign = function ( + obj /*from1, from2, from3, ...*/ + ) { + var sources = Array.prototype.slice.call( + arguments, + 1 + ); + while ( sources.length ) { + var source = sources.shift(); + if ( ! source ) { + continue; + } + + if ( typeof source !== 'object' ) { + throw new TypeError( + source + 'must be non-object' + ); + } + + for ( var p in source ) { + if ( _has( source, p ) ) { + obj[ p ] = source[ p ]; + } + } + } + + return obj; + }; + + // reduce buffer size, avoiding mem copy + exports.shrinkBuf = function ( buf, size ) { + if ( buf.length === size ) { + return buf; + } + if ( buf.subarray ) { + return buf.subarray( 0, size ); + } + buf.length = size; + return buf; + }; + + var fnTyped = { + arraySet: function ( + dest, + src, + src_offs, + len, + dest_offs + ) { + if ( src.subarray && dest.subarray ) { + dest.set( + src.subarray( src_offs, src_offs + len ), + dest_offs + ); + return; + } + // Fallback to ordinary array + for ( var i = 0; i < len; i++ ) { + dest[ dest_offs + i ] = src[ src_offs + i ]; + } + }, + // Join array of chunks to single array. + flattenChunks: function ( chunks ) { + var i, l, len, pos, chunk, result; + + // calculate data length + len = 0; + for ( i = 0, l = chunks.length; i < l; i++ ) { + len += chunks[ i ].length; + } + + // join chunks + result = new Uint8Array( len ); + pos = 0; + for ( i = 0, l = chunks.length; i < l; i++ ) { + chunk = chunks[ i ]; + result.set( chunk, pos ); + pos += chunk.length; + } + + return result; + }, + }; + + var fnUntyped = { + arraySet: function ( + dest, + src, + src_offs, + len, + dest_offs + ) { + for ( var i = 0; i < len; i++ ) { + dest[ dest_offs + i ] = src[ src_offs + i ]; + } + }, + // Join array of chunks to single array. + flattenChunks: function ( chunks ) { + return [].concat.apply( [], chunks ); + }, + }; + + // Enable/Disable typed arrays use, for testing + // + exports.setTyped = function ( on ) { + if ( on ) { + exports.Buf8 = Uint8Array; + exports.Buf16 = Uint16Array; + exports.Buf32 = Int32Array; + exports.assign( exports, fnTyped ); + } else { + exports.Buf8 = Array; + exports.Buf16 = Array; + exports.Buf32 = Array; + exports.assign( exports, fnUntyped ); + } + }; + + exports.setTyped( TYPED_OK ); + }, + {}, + ], + 2: [ + function ( require, module, exports ) { + // String encode/decode helpers + 'use strict'; + + var utils = require( './common' ); + + // Quick check if we can use fast array to bin string conversion + // + // - apply(Array) can fail on Android 2.2 + // - apply(Uint8Array) can fail on iOS 5.1 Safari + // + var STR_APPLY_OK = true; + var STR_APPLY_UIA_OK = true; + + try { + String.fromCharCode.apply( null, [ 0 ] ); + } catch ( __ ) { + STR_APPLY_OK = false; + } + try { + String.fromCharCode.apply( null, new Uint8Array( 1 ) ); + } catch ( __ ) { + STR_APPLY_UIA_OK = false; + } + + // Table with utf8 lengths (calculated by first byte of sequence) + // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, + // because max possible codepoint is 0x10ffff + var _utf8len = new utils.Buf8( 256 ); + for ( var q = 0; q < 256; q++ ) { + _utf8len[ q ] = + q >= 252 + ? 6 + : q >= 248 + ? 5 + : q >= 240 + ? 4 + : q >= 224 + ? 3 + : q >= 192 + ? 2 + : 1; + } + _utf8len[ 254 ] = _utf8len[ 254 ] = 1; // Invalid sequence start + + // convert string to array (typed, when possible) + exports.string2buf = function ( str ) { + var buf, + c, + c2, + m_pos, + i, + str_len = str.length, + buf_len = 0; + + // count binary size + for ( m_pos = 0; m_pos < str_len; m_pos++ ) { + c = str.charCodeAt( m_pos ); + if ( + ( c & 0xfc00 ) === 0xd800 && + m_pos + 1 < str_len + ) { + c2 = str.charCodeAt( m_pos + 1 ); + if ( ( c2 & 0xfc00 ) === 0xdc00 ) { + c = + 0x10000 + + ( ( c - 0xd800 ) << 10 ) + + ( c2 - 0xdc00 ); + m_pos++; + } + } + buf_len += + c < 0x80 + ? 1 + : c < 0x800 + ? 2 + : c < 0x10000 + ? 3 + : 4; + } + + // allocate buffer + buf = new utils.Buf8( buf_len ); + + // convert + for ( i = 0, m_pos = 0; i < buf_len; m_pos++ ) { + c = str.charCodeAt( m_pos ); + if ( + ( c & 0xfc00 ) === 0xd800 && + m_pos + 1 < str_len + ) { + c2 = str.charCodeAt( m_pos + 1 ); + if ( ( c2 & 0xfc00 ) === 0xdc00 ) { + c = + 0x10000 + + ( ( c - 0xd800 ) << 10 ) + + ( c2 - 0xdc00 ); + m_pos++; + } + } + if ( c < 0x80 ) { + /* one byte */ + buf[ i++ ] = c; + } else if ( c < 0x800 ) { + /* two bytes */ + buf[ i++ ] = 0xc0 | ( c >>> 6 ); + buf[ i++ ] = 0x80 | ( c & 0x3f ); + } else if ( c < 0x10000 ) { + /* three bytes */ + buf[ i++ ] = 0xe0 | ( c >>> 12 ); + buf[ i++ ] = 0x80 | ( ( c >>> 6 ) & 0x3f ); + buf[ i++ ] = 0x80 | ( c & 0x3f ); + } else { + /* four bytes */ + buf[ i++ ] = 0xf0 | ( c >>> 18 ); + buf[ i++ ] = 0x80 | ( ( c >>> 12 ) & 0x3f ); + buf[ i++ ] = 0x80 | ( ( c >>> 6 ) & 0x3f ); + buf[ i++ ] = 0x80 | ( c & 0x3f ); + } + } + + return buf; + }; + + // Helper (used in 2 places) + function buf2binstring( buf, len ) { + // On Chrome, the arguments in a function call that are allowed is `65534`. + // If the length of the buffer is smaller than that, we can use this optimization, + // otherwise we will take a slower path. + if ( len < 65534 ) { + if ( + ( buf.subarray && STR_APPLY_UIA_OK ) || + ( ! buf.subarray && STR_APPLY_OK ) + ) { + return String.fromCharCode.apply( + null, + utils.shrinkBuf( buf, len ) + ); + } + } + + var result = ''; + for ( var i = 0; i < len; i++ ) { + result += String.fromCharCode( buf[ i ] ); + } + return result; + } + + // Convert byte array to binary string + exports.buf2binstring = function ( buf ) { + return buf2binstring( buf, buf.length ); + }; + + // Convert binary string (typed, when possible) + exports.binstring2buf = function ( str ) { + var buf = new utils.Buf8( str.length ); + for ( var i = 0, len = buf.length; i < len; i++ ) { + buf[ i ] = str.charCodeAt( i ); + } + return buf; + }; + + // convert array to string + exports.buf2string = function ( buf, max ) { + var i, out, c, c_len; + var len = max || buf.length; + + // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + var utf16buf = new Array( len * 2 ); + + for ( out = 0, i = 0; i < len; ) { + c = buf[ i++ ]; + // quick process ascii + if ( c < 0x80 ) { + utf16buf[ out++ ] = c; + continue; + } + + c_len = _utf8len[ c ]; + // skip 5 & 6 byte codes + if ( c_len > 4 ) { + utf16buf[ out++ ] = 0xfffd; + i += c_len - 1; + continue; + } + + // apply mask on first byte + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; + // join the rest + while ( c_len > 1 && i < len ) { + c = ( c << 6 ) | ( buf[ i++ ] & 0x3f ); + c_len--; + } + + // terminated by end of string? + if ( c_len > 1 ) { + utf16buf[ out++ ] = 0xfffd; + continue; + } + + if ( c < 0x10000 ) { + utf16buf[ out++ ] = c; + } else { + c -= 0x10000; + utf16buf[ out++ ] = + 0xd800 | ( ( c >> 10 ) & 0x3ff ); + utf16buf[ out++ ] = 0xdc00 | ( c & 0x3ff ); + } + } + + return buf2binstring( utf16buf, out ); + }; + + // Calculate max possible position in utf8 buffer, + // that will not break sequence. If that's not possible + // - (very small limits) return max size as is. + // + // buf[] - utf8 bytes array + // max - length limit (mandatory); + exports.utf8border = function ( buf, max ) { + var pos; + + max = max || buf.length; + if ( max > buf.length ) { + max = buf.length; + } + + // go back from last position, until start of sequence found + pos = max - 1; + while ( pos >= 0 && ( buf[ pos ] & 0xc0 ) === 0x80 ) { + pos--; + } + + // Very small and broken sequence, + // return max, because we should return something anyway. + if ( pos < 0 ) { + return max; + } + + // If we came to start of buffer - that means buffer is too small, + // return max too. + if ( pos === 0 ) { + return max; + } + + return pos + _utf8len[ buf[ pos ] ] > max ? pos : max; + }; + }, + { './common': 1 }, + ], + 3: [ + function ( require, module, exports ) { + 'use strict'; + + // Note: adler32 takes 12% for level 0 and 2% for level 6. + // It isn't worth it to make additional optimizations as in original. + // Small size is preferable. + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + function adler32( adler, buf, len, pos ) { + var s1 = ( adler & 0xffff ) | 0, + s2 = ( ( adler >>> 16 ) & 0xffff ) | 0, + n = 0; + + while ( len !== 0 ) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = ( s1 + buf[ pos++ ] ) | 0; + s2 = ( s2 + s1 ) | 0; + } while ( --n ); + + s1 %= 65521; + s2 %= 65521; + } + + return s1 | ( s2 << 16 ) | 0; + } + + module.exports = adler32; + }, + {}, + ], + 4: [ + function ( require, module, exports ) { + 'use strict'; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + module.exports = { + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + //Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + //Z_VERSION_ERROR: -6, + + /* compression levels */ + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + /* Possible values of the data_type field (though see inflate()) */ + Z_BINARY: 0, + Z_TEXT: 1, + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8, + //Z_NULL: null // Use -1 or null inline, depending on var type + }; + }, + {}, + ], + 5: [ + function ( require, module, exports ) { + 'use strict'; + + // Note: we can't get significant speed boost here. + // So write code to minimize size - no pregenerated tables + // and array tools dependencies. + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // Use ordinary array, since untyped makes no boost here + function makeTable() { + var c, + table = []; + + for ( var n = 0; n < 256; n++ ) { + c = n; + for ( var k = 0; k < 8; k++ ) { + c = c & 1 ? 0xedb88320 ^ ( c >>> 1 ) : c >>> 1; + } + table[ n ] = c; + } + + return table; + } + + // Create table on load. Just 255 signed longs. Not a problem. + var crcTable = makeTable(); + + function crc32( crc, buf, len, pos ) { + var t = crcTable, + end = pos + len; + + crc ^= -1; + + for ( var i = pos; i < end; i++ ) { + crc = + ( crc >>> 8 ) ^ t[ ( crc ^ buf[ i ] ) & 0xff ]; + } + + return crc ^ -1; // >>> 0; + } + + module.exports = crc32; + }, + {}, + ], + 6: [ + function ( require, module, exports ) { + 'use strict'; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + function GZheader() { + /* true if compressed data believed to be text */ + this.text = 0; + /* modification time */ + this.time = 0; + /* extra flags (not used when writing a gzip file) */ + this.xflags = 0; + /* operating system */ + this.os = 0; + /* pointer to extra field or Z_NULL if none */ + this.extra = null; + /* extra field length (valid if extra != Z_NULL) */ + this.extra_len = 0; // Actually, we don't need it in JS, + // but leave for few code modifications + + // + // Setup limits is not necessary because in js we should not preallocate memory + // for inflate use constant limit in 65536 bytes + // + + /* space at extra (only when reading header) */ + // this.extra_max = 0; + /* pointer to zero-terminated file name or Z_NULL */ + this.name = ''; + /* space at name (only when reading header) */ + // this.name_max = 0; + /* pointer to zero-terminated comment or Z_NULL */ + this.comment = ''; + /* space at comment (only when reading header) */ + // this.comm_max = 0; + /* true if there was or will be a header crc */ + this.hcrc = 0; + /* true when done reading gzip header (not used when writing a gzip file) */ + this.done = false; + } + + module.exports = GZheader; + }, + {}, + ], + 7: [ + function ( require, module, exports ) { + 'use strict'; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // See state defs from inflate.js + var BAD = 30; /* got a data error -- remain here until reset */ + var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + + /* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state.mode === LEN + strm.avail_in >= 6 + strm.avail_out >= 258 + start >= strm.avail_out + state.bits < 8 + + On return, state.mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm.avail_out >= 258 for each loop to avoid checking for + output space. + */ + module.exports = function inflate_fast( strm, start ) { + var state; + var _in; /* local strm.input */ + var last; /* have enough input while in < last */ + var _out; /* local strm.output */ + var beg; /* inflate()'s initial strm.output */ + var end; /* while out < end, enough space available */ + //#ifdef INFLATE_STRICT + var dmax; /* maximum distance from zlib header */ + //#endif + var wsize; /* window size or zero if not using window */ + var whave; /* valid bytes in the window */ + var wnext; /* window write index */ + // Use `s_window` instead `window`, avoid conflict with instrumentation tools + var s_window; /* allocated sliding window, if wsize != 0 */ + var hold; /* local strm.hold */ + var bits; /* local strm.bits */ + var lcode; /* local strm.lencode */ + var dcode; /* local strm.distcode */ + var lmask; /* mask for first level of length codes */ + var dmask; /* mask for first level of distance codes */ + var here; /* retrieved table entry */ + var op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + var len; /* match length, unused bytes */ + var dist; /* match distance */ + var from; /* where to copy match from */ + var from_source; + + var input, output; // JS specific, because we have no pointers + + /* copy state to local variables */ + state = strm.state; + //here = state.here; + _in = strm.next_in; + input = strm.input; + last = _in + ( strm.avail_in - 5 ); + _out = strm.next_out; + output = strm.output; + beg = _out - ( start - strm.avail_out ); + end = _out + ( strm.avail_out - 257 ); + //#ifdef INFLATE_STRICT + dmax = state.dmax; + //#endif + wsize = state.wsize; + whave = state.whave; + wnext = state.wnext; + s_window = state.window; + hold = state.hold; + bits = state.bits; + lcode = state.lencode; + dcode = state.distcode; + lmask = ( 1 << state.lenbits ) - 1; + dmask = ( 1 << state.distbits ) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + top: do { + if ( bits < 15 ) { + hold += input[ _in++ ] << bits; + bits += 8; + hold += input[ _in++ ] << bits; + bits += 8; + } + + here = lcode[ hold & lmask ]; + + dolen: for (;;) { + // Goto emulation + op = here >>> 24 /*here.bits*/; + hold >>>= op; + bits -= op; + op = ( here >>> 16 ) & 0xff /*here.op*/; + if ( op === 0 ) { + /* literal */ + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + output[ _out++ ] = + here & 0xffff /*here.val*/; + } else if ( op & 16 ) { + /* length base */ + len = here & 0xffff /*here.val*/; + op &= 15; /* number of extra bits */ + if ( op ) { + if ( bits < op ) { + hold += input[ _in++ ] << bits; + bits += 8; + } + len += hold & ( ( 1 << op ) - 1 ); + hold >>>= op; + bits -= op; + } + //Tracevv((stderr, "inflate: length %u\n", len)); + if ( bits < 15 ) { + hold += input[ _in++ ] << bits; + bits += 8; + hold += input[ _in++ ] << bits; + bits += 8; + } + here = dcode[ hold & dmask ]; + + dodist: for (;;) { + // goto emulation + op = here >>> 24 /*here.bits*/; + hold >>>= op; + bits -= op; + op = ( here >>> 16 ) & 0xff /*here.op*/; + + if ( op & 16 ) { + /* distance base */ + dist = here & 0xffff /*here.val*/; + op &= 15; /* number of extra bits */ + if ( bits < op ) { + hold += input[ _in++ ] << bits; + bits += 8; + if ( bits < op ) { + hold += + input[ _in++ ] << bits; + bits += 8; + } + } + dist += hold & ( ( 1 << op ) - 1 ); + //#ifdef INFLATE_STRICT + if ( dist > dmax ) { + strm.msg = + 'invalid distance too far back'; + state.mode = BAD; + break top; + } + //#endif + hold >>>= op; + bits -= op; + //Tracevv((stderr, "inflate: distance %u\n", dist)); + op = + _out - + beg; /* max distance in output */ + if ( dist > op ) { + /* see if copy from window */ + op = + dist - + op; /* distance back in window */ + if ( op > whave ) { + if ( state.sane ) { + strm.msg = + 'invalid distance too far back'; + state.mode = BAD; + break top; + } + + // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + // if (len <= op - whave) { + // do { + // output[_out++] = 0; + // } while (--len); + // continue top; + // } + // len -= op - whave; + // do { + // output[_out++] = 0; + // } while (--op > whave); + // if (op === 0) { + // from = _out - dist; + // do { + // output[_out++] = output[from++]; + // } while (--len); + // continue top; + // } + //#endif + } + from = 0; // window index + from_source = s_window; + if ( wnext === 0 ) { + /* very common case */ + from += wsize - op; + if ( op < len ) { + /* some from window */ + len -= op; + do { + output[ _out++ ] = + s_window[ + from++ + ]; + } while ( --op ); + from = + _out - + dist; /* rest from output */ + from_source = output; + } + } else if ( wnext < op ) { + /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if ( op < len ) { + /* some from end of window */ + len -= op; + do { + output[ _out++ ] = + s_window[ + from++ + ]; + } while ( --op ); + from = 0; + if ( wnext < len ) { + /* some from start of window */ + op = wnext; + len -= op; + do { + output[ + _out++ + ] = + s_window[ + from++ + ]; + } while ( --op ); + from = + _out - + dist; /* rest from output */ + from_source = + output; + } + } + } else { + /* contiguous in window */ + from += wnext - op; + if ( op < len ) { + /* some from window */ + len -= op; + do { + output[ _out++ ] = + s_window[ + from++ + ]; + } while ( --op ); + from = + _out - + dist; /* rest from output */ + from_source = output; + } + } + while ( len > 2 ) { + output[ _out++ ] = + from_source[ from++ ]; + output[ _out++ ] = + from_source[ from++ ]; + output[ _out++ ] = + from_source[ from++ ]; + len -= 3; + } + if ( len ) { + output[ _out++ ] = + from_source[ from++ ]; + if ( len > 1 ) { + output[ _out++ ] = + from_source[ + from++ + ]; + } + } + } else { + from = + _out - + dist; /* copy direct from output */ + do { + /* minimum length is three */ + output[ _out++ ] = + output[ from++ ]; + output[ _out++ ] = + output[ from++ ]; + output[ _out++ ] = + output[ from++ ]; + len -= 3; + } while ( len > 2 ); + if ( len ) { + output[ _out++ ] = + output[ from++ ]; + if ( len > 1 ) { + output[ _out++ ] = + output[ from++ ]; + } + } + } + } else if ( ( op & 64 ) === 0 ) { + /* 2nd level distance code */ + here = + dcode[ + ( here & + 0xffff ) /*here.val*/ + + ( hold & + ( ( 1 << op ) - + 1 ) ) + ]; + continue dodist; + } else { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } else if ( ( op & 64 ) === 0 ) { + /* 2nd level length code */ + here = + lcode[ + ( here & 0xffff ) /*here.val*/ + + ( hold & ( ( 1 << op ) - 1 ) ) + ]; + continue dolen; + } else if ( op & 32 ) { + /* end-of-block */ + //Tracevv((stderr, "inflate: end of block\n")); + state.mode = TYPE; + break top; + } else { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } while ( _in < last && _out < end ); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + _in -= len; + bits -= len << 3; + hold &= ( 1 << bits ) - 1; + + /* update state and return */ + strm.next_in = _in; + strm.next_out = _out; + strm.avail_in = + _in < last + ? 5 + ( last - _in ) + : 5 - ( _in - last ); + strm.avail_out = + _out < end + ? 257 + ( end - _out ) + : 257 - ( _out - end ); + state.hold = hold; + state.bits = bits; + return; + }; + }, + {}, + ], + 8: [ + function ( require, module, exports ) { + 'use strict'; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + var utils = require( '../utils/common' ); + var adler32 = require( './adler32' ); + var crc32 = require( './crc32' ); + var inflate_fast = require( './inffast' ); + var inflate_table = require( './inftrees' ); + + var CODES = 0; + var LENS = 1; + var DISTS = 2; + + /* Public constants ==========================================================*/ + /* ===========================================================================*/ + + /* Allowed flush values; see deflate() and inflate() below for details */ + //var Z_NO_FLUSH = 0; + //var Z_PARTIAL_FLUSH = 1; + //var Z_SYNC_FLUSH = 2; + //var Z_FULL_FLUSH = 3; + var Z_FINISH = 4; + var Z_BLOCK = 5; + var Z_TREES = 6; + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + var Z_OK = 0; + var Z_STREAM_END = 1; + var Z_NEED_DICT = 2; + //var Z_ERRNO = -1; + var Z_STREAM_ERROR = -2; + var Z_DATA_ERROR = -3; + var Z_MEM_ERROR = -4; + var Z_BUF_ERROR = -5; + //var Z_VERSION_ERROR = -6; + + /* The deflate compression method */ + var Z_DEFLATED = 8; + + /* STATES ====================================================================*/ + /* ===========================================================================*/ + + var HEAD = 1; /* i: waiting for magic header */ + var FLAGS = 2; /* i: waiting for method and flags (gzip) */ + var TIME = 3; /* i: waiting for modification time (gzip) */ + var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ + var EXLEN = 5; /* i: waiting for extra length (gzip) */ + var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ + var NAME = 7; /* i: waiting for end of file name (gzip) */ + var COMMENT = 8; /* i: waiting for end of comment (gzip) */ + var HCRC = 9; /* i: waiting for header crc (gzip) */ + var DICTID = 10; /* i: waiting for dictionary check value */ + var DICT = 11; /* waiting for inflateSetDictionary() call */ + var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ + var STORED = 14; /* i: waiting for stored size (length and complement) */ + var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ + var COPY = 16; /* i/o: waiting for input or output to copy stored block */ + var TABLE = 17; /* i: waiting for dynamic block table lengths */ + var LENLENS = 18; /* i: waiting for code length code lengths */ + var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ + var LEN_ = 20; /* i: same as LEN below, but only first time in */ + var LEN = 21; /* i: waiting for length/lit/eob code */ + var LENEXT = 22; /* i: waiting for length extra bits */ + var DIST = 23; /* i: waiting for distance code */ + var DISTEXT = 24; /* i: waiting for distance extra bits */ + var MATCH = 25; /* o: waiting for output space to copy string */ + var LIT = 26; /* o: waiting for output space to write literal */ + var CHECK = 27; /* i: waiting for 32-bit check value */ + var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ + var DONE = 29; /* finished check, done -- remain here until reset */ + var BAD = 30; /* got a data error -- remain here until reset */ + var MEM = 31; /* got an inflate() memory error -- remain here until reset */ + var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ + + /* ===========================================================================*/ + + var ENOUGH_LENS = 852; + var ENOUGH_DISTS = 592; + //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + + var MAX_WBITS = 15; + /* 32K LZ77 window */ + var DEF_WBITS = MAX_WBITS; + + function zswap32( q ) { + return ( + ( ( q >>> 24 ) & 0xff ) + + ( ( q >>> 8 ) & 0xff00 ) + + ( ( q & 0xff00 ) << 8 ) + + ( ( q & 0xff ) << 24 ) + ); + } + + function InflateState() { + this.mode = 0; /* current inflate mode */ + this.last = false; /* true if processing last block */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.havedict = false; /* true if dictionary provided */ + this.flags = 0; /* gzip header method and flags (0 if zlib) */ + this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ + this.check = 0; /* protected copy of check value */ + this.total = 0; /* protected copy of output count */ + // TODO: may be {} + this.head = + null; /* where to save gzip header information */ + + /* sliding window */ + this.wbits = 0; /* log base 2 of requested window size */ + this.wsize = 0; /* window size or zero if not using window */ + this.whave = 0; /* valid bytes in the window */ + this.wnext = 0; /* window write index */ + this.window = + null; /* allocated sliding window, if needed */ + + /* bit accumulator */ + this.hold = 0; /* input bit accumulator */ + this.bits = 0; /* number of bits in "in" */ + + /* for string and stored block copying */ + this.length = 0; /* literal or length of data to copy */ + this.offset = 0; /* distance back to copy string from */ + + /* for table and code decoding */ + this.extra = 0; /* extra bits needed */ + + /* fixed and dynamic code tables */ + this.lencode = + null; /* starting table for length/literal codes */ + this.distcode = + null; /* starting table for distance codes */ + this.lenbits = 0; /* index bits for lencode */ + this.distbits = 0; /* index bits for distcode */ + + /* dynamic table building */ + this.ncode = 0; /* number of code length code lengths */ + this.nlen = 0; /* number of length code lengths */ + this.ndist = 0; /* number of distance code lengths */ + this.have = 0; /* number of code lengths in lens[] */ + this.next = null; /* next available space in codes[] */ + + this.lens = new utils.Buf16( + 320 + ); /* temporary storage for code lengths */ + this.work = new utils.Buf16( + 288 + ); /* work area for code table building */ + + /* + because we don't have pointers in js, we use lencode and distcode directly + as buffers so we don't need codes + */ + //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ + this.lendyn = + null; /* dynamic table for length/literal codes (JS specific) */ + this.distdyn = + null; /* dynamic table for distance codes (JS specific) */ + this.sane = 0; /* if false, allow invalid distance too far */ + this.back = 0; /* bits back of last unprocessed length/lit */ + this.was = 0; /* initial length of match */ + } + + function inflateResetKeep( strm ) { + var state; + + if ( ! strm || ! strm.state ) { + return Z_STREAM_ERROR; + } + state = strm.state; + strm.total_in = strm.total_out = state.total = 0; + strm.msg = ''; /*Z_NULL*/ + if ( state.wrap ) { + /* to support ill-conceived Java test suite */ + strm.adler = state.wrap & 1; + } + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768; + state.head = null /*Z_NULL*/; + state.hold = 0; + state.bits = 0; + //state.lencode = state.distcode = state.next = state.codes; + state.lencode = state.lendyn = new utils.Buf32( + ENOUGH_LENS + ); + state.distcode = state.distdyn = new utils.Buf32( + ENOUGH_DISTS + ); + + state.sane = 1; + state.back = -1; + //Tracev((stderr, "inflate: reset\n")); + return Z_OK; + } + + function inflateReset( strm ) { + var state; + + if ( ! strm || ! strm.state ) { + return Z_STREAM_ERROR; + } + state = strm.state; + state.wsize = 0; + state.whave = 0; + state.wnext = 0; + return inflateResetKeep( strm ); + } + + function inflateReset2( strm, windowBits ) { + var wrap; + var state; + + /* get the state */ + if ( ! strm || ! strm.state ) { + return Z_STREAM_ERROR; + } + state = strm.state; + + /* extract wrap request from windowBits parameter */ + if ( windowBits < 0 ) { + wrap = 0; + windowBits = -windowBits; + } else { + wrap = ( windowBits >> 4 ) + 1; + if ( windowBits < 48 ) { + windowBits &= 15; + } + } + + /* set number of window bits, free window if different */ + if ( + windowBits && + ( windowBits < 8 || windowBits > 15 ) + ) { + return Z_STREAM_ERROR; + } + if ( + state.window !== null && + state.wbits !== windowBits + ) { + state.window = null; + } + + /* update state and reset the rest of it */ + state.wrap = wrap; + state.wbits = windowBits; + return inflateReset( strm ); + } + + function inflateInit2( strm, windowBits ) { + var ret; + var state; + + if ( ! strm ) { + return Z_STREAM_ERROR; + } + //strm.msg = Z_NULL; /* in case we return an error */ + + state = new InflateState(); + + //if (state === Z_NULL) return Z_MEM_ERROR; + //Tracev((stderr, "inflate: allocated\n")); + strm.state = state; + state.window = null /*Z_NULL*/; + ret = inflateReset2( strm, windowBits ); + if ( ret !== Z_OK ) { + strm.state = null /*Z_NULL*/; + } + return ret; + } + + function inflateInit( strm ) { + return inflateInit2( strm, DEF_WBITS ); + } + + /* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ + var virgin = true; + + var lenfix, distfix; // We have no pointers in JS, so keep tables separate + + function fixedtables( state ) { + /* build fixed huffman tables if first call (may not be thread safe) */ + if ( virgin ) { + var sym; + + lenfix = new utils.Buf32( 512 ); + distfix = new utils.Buf32( 32 ); + + /* literal/length table */ + sym = 0; + while ( sym < 144 ) { + state.lens[ sym++ ] = 8; + } + while ( sym < 256 ) { + state.lens[ sym++ ] = 9; + } + while ( sym < 280 ) { + state.lens[ sym++ ] = 7; + } + while ( sym < 288 ) { + state.lens[ sym++ ] = 8; + } + + inflate_table( + LENS, + state.lens, + 0, + 288, + lenfix, + 0, + state.work, + { bits: 9 } + ); + + /* distance table */ + sym = 0; + while ( sym < 32 ) { + state.lens[ sym++ ] = 5; + } + + inflate_table( + DISTS, + state.lens, + 0, + 32, + distfix, + 0, + state.work, + { bits: 5 } + ); + + /* do this just once */ + virgin = false; + } + + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; + } + + /* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ + function updatewindow( strm, src, end, copy ) { + var dist; + var state = strm.state; + + /* if it hasn't been done already, allocate space for the window */ + if ( state.window === null ) { + state.wsize = 1 << state.wbits; + state.wnext = 0; + state.whave = 0; + + state.window = new utils.Buf8( state.wsize ); + } + + /* copy state->wsize or less output bytes into the circular window */ + if ( copy >= state.wsize ) { + utils.arraySet( + state.window, + src, + end - state.wsize, + state.wsize, + 0 + ); + state.wnext = 0; + state.whave = state.wsize; + } else { + dist = state.wsize - state.wnext; + if ( dist > copy ) { + dist = copy; + } + //zmemcpy(state->window + state->wnext, end - copy, dist); + utils.arraySet( + state.window, + src, + end - copy, + dist, + state.wnext + ); + copy -= dist; + if ( copy ) { + //zmemcpy(state->window, end - copy, copy); + utils.arraySet( + state.window, + src, + end - copy, + copy, + 0 + ); + state.wnext = copy; + state.whave = state.wsize; + } else { + state.wnext += dist; + if ( state.wnext === state.wsize ) { + state.wnext = 0; + } + if ( state.whave < state.wsize ) { + state.whave += dist; + } + } + } + return 0; + } + + function inflate( strm, flush ) { + var state; + var input, output; // input/output buffers + var next; /* next input INDEX */ + var put; /* next output INDEX */ + var have, left; /* available input and output */ + var hold; /* bit buffer */ + var bits; /* bits in bit buffer */ + var _in, + _out; /* save starting available input and output */ + var copy; /* number of stored or match bytes to copy */ + var from; /* where to copy match bytes from */ + var from_source; + var here = 0; /* current decoding table entry */ + var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) + //var last; /* parent table entry */ + var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) + var len; /* length to copy for repeats, bits to drop */ + var ret; /* return code */ + var hbuf = new utils.Buf8( + 4 + ); /* buffer for gzip header crc calculation */ + var opts; + + var n; // temporary var for NEED_BITS + + var order = + /* permutation of code lengths */ + [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, + 13, 2, 14, 1, 15, + ]; + + if ( + ! strm || + ! strm.state || + ! strm.output || + ( ! strm.input && strm.avail_in !== 0 ) + ) { + return Z_STREAM_ERROR; + } + + state = strm.state; + if ( state.mode === TYPE ) { + state.mode = TYPEDO; + } /* skip check */ + + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + _in = have; + _out = left; + ret = Z_OK; + + // goto emulation + inf_leave: for (;;) { + switch ( state.mode ) { + case HEAD: + if ( state.wrap === 0 ) { + state.mode = TYPEDO; + break; + } + //=== NEEDBITS(16); + while ( bits < 16 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + if ( state.wrap & 2 && hold === 0x8b1f ) { + /* gzip header */ + state.check = 0 /*crc32(0L, Z_NULL, 0)*/; + //=== CRC2(state.check, hold); + hbuf[ 0 ] = hold & 0xff; + hbuf[ 1 ] = ( hold >>> 8 ) & 0xff; + state.check = crc32( + state.check, + hbuf, + 2, + 0 + ); + //===// + + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = FLAGS; + break; + } + state.flags = 0; /* expect zlib header */ + if ( state.head ) { + state.head.done = false; + } + if ( + ! ( + state.wrap & 1 + ) /* check if zlib header allowed */ || + ( ( ( hold & 0xff ) /*BITS(8)*/ << 8 ) + + ( hold >> 8 ) ) % + 31 + ) { + strm.msg = 'incorrect header check'; + state.mode = BAD; + break; + } + if ( + ( hold & 0x0f ) /*BITS(4)*/ !== + Z_DEFLATED + ) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + len = ( hold & 0x0f ) /*BITS(4)*/ + 8; + if ( state.wbits === 0 ) { + state.wbits = len; + } else if ( len > state.wbits ) { + strm.msg = 'invalid window size'; + state.mode = BAD; + break; + } + state.dmax = 1 << len; + //Tracev((stderr, "inflate: zlib header ok\n")); + strm.adler = + state.check = 1 /*adler32(0L, Z_NULL, 0)*/; + state.mode = hold & 0x200 ? DICTID : TYPE; + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + break; + case FLAGS: + //=== NEEDBITS(16); */ + while ( bits < 16 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + state.flags = hold; + if ( + ( state.flags & 0xff ) !== + Z_DEFLATED + ) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + if ( state.flags & 0xe000 ) { + strm.msg = 'unknown header flags set'; + state.mode = BAD; + break; + } + if ( state.head ) { + state.head.text = ( hold >> 8 ) & 1; + } + if ( state.flags & 0x0200 ) { + //=== CRC2(state.check, hold); + hbuf[ 0 ] = hold & 0xff; + hbuf[ 1 ] = ( hold >>> 8 ) & 0xff; + state.check = crc32( + state.check, + hbuf, + 2, + 0 + ); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = TIME; + /* falls through */ + case TIME: + //=== NEEDBITS(32); */ + while ( bits < 32 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + if ( state.head ) { + state.head.time = hold; + } + if ( state.flags & 0x0200 ) { + //=== CRC4(state.check, hold) + hbuf[ 0 ] = hold & 0xff; + hbuf[ 1 ] = ( hold >>> 8 ) & 0xff; + hbuf[ 2 ] = ( hold >>> 16 ) & 0xff; + hbuf[ 3 ] = ( hold >>> 24 ) & 0xff; + state.check = crc32( + state.check, + hbuf, + 4, + 0 + ); + //=== + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = OS; + /* falls through */ + case OS: + //=== NEEDBITS(16); */ + while ( bits < 16 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + if ( state.head ) { + state.head.xflags = hold & 0xff; + state.head.os = hold >> 8; + } + if ( state.flags & 0x0200 ) { + //=== CRC2(state.check, hold); + hbuf[ 0 ] = hold & 0xff; + hbuf[ 1 ] = ( hold >>> 8 ) & 0xff; + state.check = crc32( + state.check, + hbuf, + 2, + 0 + ); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = EXLEN; + /* falls through */ + case EXLEN: + if ( state.flags & 0x0400 ) { + //=== NEEDBITS(16); */ + while ( bits < 16 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + state.length = hold; + if ( state.head ) { + state.head.extra_len = hold; + } + if ( state.flags & 0x0200 ) { + //=== CRC2(state.check, hold); + hbuf[ 0 ] = hold & 0xff; + hbuf[ 1 ] = ( hold >>> 8 ) & 0xff; + state.check = crc32( + state.check, + hbuf, + 2, + 0 + ); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } else if ( state.head ) { + state.head.extra = null /*Z_NULL*/; + } + state.mode = EXTRA; + /* falls through */ + case EXTRA: + if ( state.flags & 0x0400 ) { + copy = state.length; + if ( copy > have ) { + copy = have; + } + if ( copy ) { + if ( state.head ) { + len = + state.head.extra_len - + state.length; + if ( ! state.head.extra ) { + // Use untyped array for more convenient processing later + state.head.extra = + new Array( + state.head.extra_len + ); + } + utils.arraySet( + state.head.extra, + input, + next, + // extra field is limited to 65536 bytes + // - no need for additional size check + copy, + /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ + len + ); + //zmemcpy(state.head.extra + len, next, + // len + copy > state.head.extra_max ? + // state.head.extra_max - len : copy); + } + if ( state.flags & 0x0200 ) { + state.check = crc32( + state.check, + input, + copy, + next + ); + } + have -= copy; + next += copy; + state.length -= copy; + } + if ( state.length ) { + break inf_leave; + } + } + state.length = 0; + state.mode = NAME; + /* falls through */ + case NAME: + if ( state.flags & 0x0800 ) { + if ( have === 0 ) { + break inf_leave; + } + copy = 0; + do { + // TODO: 2 or 1 bytes? + len = input[ next + copy++ ]; + /* use constant limit because in js we should not preallocate memory */ + if ( + state.head && + len && + state.length < + 65536 /*state.head.name_max*/ + ) { + state.head.name += + String.fromCharCode( len ); + } + } while ( len && copy < have ); + + if ( state.flags & 0x0200 ) { + state.check = crc32( + state.check, + input, + copy, + next + ); + } + have -= copy; + next += copy; + if ( len ) { + break inf_leave; + } + } else if ( state.head ) { + state.head.name = null; + } + state.length = 0; + state.mode = COMMENT; + /* falls through */ + case COMMENT: + if ( state.flags & 0x1000 ) { + if ( have === 0 ) { + break inf_leave; + } + copy = 0; + do { + len = input[ next + copy++ ]; + /* use constant limit because in js we should not preallocate memory */ + if ( + state.head && + len && + state.length < + 65536 /*state.head.comm_max*/ + ) { + state.head.comment += + String.fromCharCode( len ); + } + } while ( len && copy < have ); + if ( state.flags & 0x0200 ) { + state.check = crc32( + state.check, + input, + copy, + next + ); + } + have -= copy; + next += copy; + if ( len ) { + break inf_leave; + } + } else if ( state.head ) { + state.head.comment = null; + } + state.mode = HCRC; + /* falls through */ + case HCRC: + if ( state.flags & 0x0200 ) { + //=== NEEDBITS(16); */ + while ( bits < 16 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + if ( + hold !== + ( state.check & 0xffff ) + ) { + strm.msg = 'header crc mismatch'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + if ( state.head ) { + state.head.hcrc = + ( state.flags >> 9 ) & 1; + state.head.done = true; + } + strm.adler = state.check = 0; + state.mode = TYPE; + break; + case DICTID: + //=== NEEDBITS(32); */ + while ( bits < 32 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + strm.adler = state.check = zswap32( hold ); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = DICT; + /* falls through */ + case DICT: + if ( state.havedict === 0 ) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + return Z_NEED_DICT; + } + strm.adler = + state.check = 1 /*adler32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + /* falls through */ + case TYPE: + if ( + flush === Z_BLOCK || + flush === Z_TREES + ) { + break inf_leave; + } + /* falls through */ + case TYPEDO: + if ( state.last ) { + //--- BYTEBITS() ---// + hold >>>= bits & 7; + bits -= bits & 7; + //---// + state.mode = CHECK; + break; + } + //=== NEEDBITS(3); */ + while ( bits < 3 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + state.last = hold & 0x01 /*BITS(1)*/; + //--- DROPBITS(1) ---// + hold >>>= 1; + bits -= 1; + //---// + + switch ( hold & 0x03 /*BITS(2)*/ ) { + case 0 /* stored block */: + //Tracev((stderr, "inflate: stored block%s\n", + // state.last ? " (last)" : "")); + state.mode = STORED; + break; + case 1 /* fixed block */: + fixedtables( state ); + //Tracev((stderr, "inflate: fixed codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = + LEN_; /* decode codes */ + if ( flush === Z_TREES ) { + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break inf_leave; + } + break; + case 2 /* dynamic block */: + //Tracev((stderr, "inflate: dynamic codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = TABLE; + break; + case 3: + strm.msg = 'invalid block type'; + state.mode = BAD; + } + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break; + case STORED: + //--- BYTEBITS() ---// /* go to byte boundary */ + hold >>>= bits & 7; + bits -= bits & 7; + //---// + //=== NEEDBITS(32); */ + while ( bits < 32 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + if ( + ( hold & 0xffff ) !== + ( ( hold >>> 16 ) ^ 0xffff ) + ) { + strm.msg = + 'invalid stored block lengths'; + state.mode = BAD; + break; + } + state.length = hold & 0xffff; + //Tracev((stderr, "inflate: stored length %u\n", + // state.length)); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = COPY_; + if ( flush === Z_TREES ) { + break inf_leave; + } + /* falls through */ + case COPY_: + state.mode = COPY; + /* falls through */ + case COPY: + copy = state.length; + if ( copy ) { + if ( copy > have ) { + copy = have; + } + if ( copy > left ) { + copy = left; + } + if ( copy === 0 ) { + break inf_leave; + } + //--- zmemcpy(put, next, copy); --- + utils.arraySet( + output, + input, + next, + copy, + put + ); + //---// + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } + //Tracev((stderr, "inflate: stored end\n")); + state.mode = TYPE; + break; + case TABLE: + //=== NEEDBITS(14); */ + while ( bits < 14 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + state.nlen = + ( hold & 0x1f ) /*BITS(5)*/ + 257; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ndist = + ( hold & 0x1f ) /*BITS(5)*/ + 1; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ncode = + ( hold & 0x0f ) /*BITS(4)*/ + 4; + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + //#ifndef PKZIP_BUG_WORKAROUND + if ( + state.nlen > 286 || + state.ndist > 30 + ) { + strm.msg = + 'too many length or distance symbols'; + state.mode = BAD; + break; + } + //#endif + //Tracev((stderr, "inflate: table sizes ok\n")); + state.have = 0; + state.mode = LENLENS; + /* falls through */ + case LENLENS: + while ( state.have < state.ncode ) { + //=== NEEDBITS(3); + while ( bits < 3 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + state.lens[ order[ state.have++ ] ] = + hold & 0x07; //BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + while ( state.have < 19 ) { + state.lens[ order[ state.have++ ] ] = 0; + } + // We have separate tables & no pointers. 2 commented lines below not needed. + //state.next = state.codes; + //state.lencode = state.next; + // Switch to use dynamic table + state.lencode = state.lendyn; + state.lenbits = 7; + + opts = { bits: state.lenbits }; + ret = inflate_table( + CODES, + state.lens, + 0, + 19, + state.lencode, + 0, + state.work, + opts + ); + state.lenbits = opts.bits; + + if ( ret ) { + strm.msg = 'invalid code lengths set'; + state.mode = BAD; + break; + } + //Tracev((stderr, "inflate: code lengths ok\n")); + state.have = 0; + state.mode = CODELENS; + /* falls through */ + case CODELENS: + while ( + state.have < + state.nlen + state.ndist + ) { + for (;;) { + here = + state.lencode[ + hold & + ( ( 1 << + state.lenbits ) - + 1 ) + ]; /*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = ( here >>> 16 ) & 0xff; + here_val = here & 0xffff; + + if ( here_bits <= bits ) { + break; + } + //--- PULLBYTE() ---// + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + //---// + } + if ( here_val < 16 ) { + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.lens[ state.have++ ] = + here_val; + } else { + if ( here_val === 16 ) { + //=== NEEDBITS(here.bits + 2); + n = here_bits + 2; + while ( bits < n ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += + input[ next++ ] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + if ( state.have === 0 ) { + strm.msg = + 'invalid bit length repeat'; + state.mode = BAD; + break; + } + len = + state.lens[ + state.have - 1 + ]; + copy = 3 + ( hold & 0x03 ); //BITS(2); + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + } else if ( here_val === 17 ) { + //=== NEEDBITS(here.bits + 3); + n = here_bits + 3; + while ( bits < n ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += + input[ next++ ] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 3 + ( hold & 0x07 ); //BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } else { + //=== NEEDBITS(here.bits + 7); + n = here_bits + 7; + while ( bits < n ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += + input[ next++ ] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 11 + ( hold & 0x7f ); //BITS(7); + //--- DROPBITS(7) ---// + hold >>>= 7; + bits -= 7; + //---// + } + if ( + state.have + copy > + state.nlen + state.ndist + ) { + strm.msg = + 'invalid bit length repeat'; + state.mode = BAD; + break; + } + while ( copy-- ) { + state.lens[ state.have++ ] = + len; + } + } + } + + /* handle error breaks in while */ + if ( state.mode === BAD ) { + break; + } + + /* check for end-of-block code (better have one) */ + if ( state.lens[ 256 ] === 0 ) { + strm.msg = + 'invalid code -- missing end-of-block'; + state.mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state.lenbits = 9; + + opts = { bits: state.lenbits }; + ret = inflate_table( + LENS, + state.lens, + 0, + state.nlen, + state.lencode, + 0, + state.work, + opts + ); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.lenbits = opts.bits; + // state.lencode = state.next; + + if ( ret ) { + strm.msg = + 'invalid literal/lengths set'; + state.mode = BAD; + break; + } + + state.distbits = 6; + //state.distcode.copy(state.codes); + // Switch to use dynamic table + state.distcode = state.distdyn; + opts = { bits: state.distbits }; + ret = inflate_table( + DISTS, + state.lens, + state.nlen, + state.ndist, + state.distcode, + 0, + state.work, + opts + ); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.distbits = opts.bits; + // state.distcode = state.next; + + if ( ret ) { + strm.msg = 'invalid distances set'; + state.mode = BAD; + break; + } + //Tracev((stderr, 'inflate: codes ok\n')); + state.mode = LEN_; + if ( flush === Z_TREES ) { + break inf_leave; + } + /* falls through */ + case LEN_: + state.mode = LEN; + /* falls through */ + case LEN: + if ( have >= 6 && left >= 258 ) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + inflate_fast( strm, _out ); + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + if ( state.mode === TYPE ) { + state.back = -1; + } + break; + } + state.back = 0; + for (;;) { + here = + state.lencode[ + hold & + ( ( 1 << state.lenbits ) - + 1 ) + ]; /*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = ( here >>> 16 ) & 0xff; + here_val = here & 0xffff; + + if ( here_bits <= bits ) { + break; + } + //--- PULLBYTE() ---// + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + //---// + } + if ( here_op && ( here_op & 0xf0 ) === 0 ) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = + state.lencode[ + last_val + + ( ( hold & + ( ( 1 << + ( last_bits + + last_op ) ) - + 1 ) ) /*BITS(last.bits + last.op)*/ >> + last_bits ) + ]; + here_bits = here >>> 24; + here_op = ( here >>> 16 ) & 0xff; + here_val = here & 0xffff; + + if ( + last_bits + here_bits <= + bits + ) { + break; + } + //--- PULLBYTE() ---// + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + state.length = here_val; + if ( here_op === 0 ) { + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + state.mode = LIT; + break; + } + if ( here_op & 32 ) { + //Tracevv((stderr, "inflate: end of block\n")); + state.back = -1; + state.mode = TYPE; + break; + } + if ( here_op & 64 ) { + strm.msg = + 'invalid literal/length code'; + state.mode = BAD; + break; + } + state.extra = here_op & 15; + state.mode = LENEXT; + /* falls through */ + case LENEXT: + if ( state.extra ) { + //=== NEEDBITS(state.extra); + n = state.extra; + while ( bits < n ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + state.length += + hold & + ( ( 1 << state.extra ) - + 1 ) /*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //Tracevv((stderr, "inflate: length %u\n", state.length)); + state.was = state.length; + state.mode = DIST; + /* falls through */ + case DIST: + for (;;) { + here = + state.distcode[ + hold & + ( ( 1 << state.distbits ) - + 1 ) + ]; /*BITS(state.distbits)*/ + here_bits = here >>> 24; + here_op = ( here >>> 16 ) & 0xff; + here_val = here & 0xffff; + + if ( here_bits <= bits ) { + break; + } + //--- PULLBYTE() ---// + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + //---// + } + if ( ( here_op & 0xf0 ) === 0 ) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = + state.distcode[ + last_val + + ( ( hold & + ( ( 1 << + ( last_bits + + last_op ) ) - + 1 ) ) /*BITS(last.bits + last.op)*/ >> + last_bits ) + ]; + here_bits = here >>> 24; + here_op = ( here >>> 16 ) & 0xff; + here_val = here & 0xffff; + + if ( + last_bits + here_bits <= + bits + ) { + break; + } + //--- PULLBYTE() ---// + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + if ( here_op & 64 ) { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break; + } + state.offset = here_val; + state.extra = here_op & 15; + state.mode = DISTEXT; + /* falls through */ + case DISTEXT: + if ( state.extra ) { + //=== NEEDBITS(state.extra); + n = state.extra; + while ( bits < n ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + state.offset += + hold & + ( ( 1 << state.extra ) - + 1 ) /*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //#ifdef INFLATE_STRICT + if ( state.offset > state.dmax ) { + strm.msg = + 'invalid distance too far back'; + state.mode = BAD; + break; + } + //#endif + //Tracevv((stderr, "inflate: distance %u\n", state.offset)); + state.mode = MATCH; + /* falls through */ + case MATCH: + if ( left === 0 ) { + break inf_leave; + } + copy = _out - left; + if ( state.offset > copy ) { + /* copy from window */ + copy = state.offset - copy; + if ( copy > state.whave ) { + if ( state.sane ) { + strm.msg = + 'invalid distance too far back'; + state.mode = BAD; + break; + } + // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + // Trace((stderr, "inflate.c too far\n")); + // copy -= state.whave; + // if (copy > state.length) { copy = state.length; } + // if (copy > left) { copy = left; } + // left -= copy; + // state.length -= copy; + // do { + // output[put++] = 0; + // } while (--copy); + // if (state.length === 0) { state.mode = LEN; } + // break; + //#endif + } + if ( copy > state.wnext ) { + copy -= state.wnext; + from = state.wsize - copy; + } else { + from = state.wnext - copy; + } + if ( copy > state.length ) { + copy = state.length; + } + from_source = state.window; + } else { + /* copy from output */ + from_source = output; + from = put - state.offset; + copy = state.length; + } + if ( copy > left ) { + copy = left; + } + left -= copy; + state.length -= copy; + do { + output[ put++ ] = from_source[ from++ ]; + } while ( --copy ); + if ( state.length === 0 ) { + state.mode = LEN; + } + break; + case LIT: + if ( left === 0 ) { + break inf_leave; + } + output[ put++ ] = state.length; + left--; + state.mode = LEN; + break; + case CHECK: + if ( state.wrap ) { + //=== NEEDBITS(32); + while ( bits < 32 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + // Use '|' instead of '+' to make sure that result is signed + hold |= input[ next++ ] << bits; + bits += 8; + } + //===// + _out -= left; + strm.total_out += _out; + state.total += _out; + if ( _out ) { + strm.adler = state.check = + /*UPDATE(state.check, put - _out, _out);*/ + state.flags + ? crc32( + state.check, + output, + _out, + put - _out + ) + : adler32( + state.check, + output, + _out, + put - _out + ); + } + _out = left; + // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too + if ( + ( state.flags + ? hold + : zswap32( hold ) ) !== + state.check + ) { + strm.msg = 'incorrect data check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: check matches trailer\n")); + } + state.mode = LENGTH; + /* falls through */ + case LENGTH: + if ( state.wrap && state.flags ) { + //=== NEEDBITS(32); + while ( bits < 32 ) { + if ( have === 0 ) { + break inf_leave; + } + have--; + hold += input[ next++ ] << bits; + bits += 8; + } + //===// + if ( + hold !== + ( state.total & 0xffffffff ) + ) { + strm.msg = 'incorrect length check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: length matches trailer\n")); + } + state.mode = DONE; + /* falls through */ + case DONE: + ret = Z_STREAM_END; + break inf_leave; + case BAD: + ret = Z_DATA_ERROR; + break inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* falls through */ + default: + return Z_STREAM_ERROR; + } + } + + // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + + if ( + state.wsize || + ( _out !== strm.avail_out && + state.mode < BAD && + ( state.mode < CHECK || flush !== Z_FINISH ) ) + ) { + if ( + updatewindow( + strm, + strm.output, + strm.next_out, + _out - strm.avail_out + ) + ) { + state.mode = MEM; + return Z_MEM_ERROR; + } + } + _in -= strm.avail_in; + _out -= strm.avail_out; + strm.total_in += _in; + strm.total_out += _out; + state.total += _out; + if ( state.wrap && _out ) { + strm.adler = state.check = + /*UPDATE(state.check, strm.next_out - _out, _out);*/ + state.flags + ? crc32( + state.check, + output, + _out, + strm.next_out - _out + ) + : adler32( + state.check, + output, + _out, + strm.next_out - _out + ); + } + strm.data_type = + state.bits + + ( state.last ? 64 : 0 ) + + ( state.mode === TYPE ? 128 : 0 ) + + ( state.mode === LEN_ || state.mode === COPY_ + ? 256 + : 0 ); + if ( + ( ( _in === 0 && _out === 0 ) || + flush === Z_FINISH ) && + ret === Z_OK + ) { + ret = Z_BUF_ERROR; + } + return ret; + } + + function inflateEnd( strm ) { + if ( + ! strm || + ! strm.state /*|| strm->zfree == (free_func)0*/ + ) { + return Z_STREAM_ERROR; + } + + var state = strm.state; + if ( state.window ) { + state.window = null; + } + strm.state = null; + return Z_OK; + } + + function inflateGetHeader( strm, head ) { + var state; + + /* check state */ + if ( ! strm || ! strm.state ) { + return Z_STREAM_ERROR; + } + state = strm.state; + if ( ( state.wrap & 2 ) === 0 ) { + return Z_STREAM_ERROR; + } + + /* save header structure */ + state.head = head; + head.done = false; + return Z_OK; + } + + function inflateSetDictionary( strm, dictionary ) { + var dictLength = dictionary.length; + + var state; + var dictid; + var ret; + + /* check state */ + if ( + ! strm /* == Z_NULL */ || + ! strm.state /* == Z_NULL */ + ) { + return Z_STREAM_ERROR; + } + state = strm.state; + + if ( state.wrap !== 0 && state.mode !== DICT ) { + return Z_STREAM_ERROR; + } + + /* check for correct dictionary identifier */ + if ( state.mode === DICT ) { + dictid = 1; /* adler32(0, null, 0)*/ + /* dictid = adler32(dictid, dictionary, dictLength); */ + dictid = adler32( + dictid, + dictionary, + dictLength, + 0 + ); + if ( dictid !== state.check ) { + return Z_DATA_ERROR; + } + } + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow( + strm, + dictionary, + dictLength, + dictLength + ); + if ( ret ) { + state.mode = MEM; + return Z_MEM_ERROR; + } + state.havedict = 1; + // Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; + } + + exports.inflateReset = inflateReset; + exports.inflateReset2 = inflateReset2; + exports.inflateResetKeep = inflateResetKeep; + exports.inflateInit = inflateInit; + exports.inflateInit2 = inflateInit2; + exports.inflate = inflate; + exports.inflateEnd = inflateEnd; + exports.inflateGetHeader = inflateGetHeader; + exports.inflateSetDictionary = inflateSetDictionary; + exports.inflateInfo = 'pako inflate (from Nodeca project)'; + + /* Not implemented + exports.inflateCopy = inflateCopy; + exports.inflateGetDictionary = inflateGetDictionary; + exports.inflateMark = inflateMark; + exports.inflatePrime = inflatePrime; + exports.inflateSync = inflateSync; + exports.inflateSyncPoint = inflateSyncPoint; + exports.inflateUndermine = inflateUndermine; + */ + }, + { + '../utils/common': 1, + './adler32': 3, + './crc32': 5, + './inffast': 7, + './inftrees': 9, + }, + ], + 9: [ + function ( require, module, exports ) { + 'use strict'; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + var utils = require( '../utils/common' ); + + var MAXBITS = 15; + var ENOUGH_LENS = 852; + var ENOUGH_DISTS = 592; + //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + + var CODES = 0; + var LENS = 1; + var DISTS = 2; + + var lbase = [ + /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, + 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, + 83, 99, 115, 131, 163, 195, 227, 258, 0, 0, + ]; + + var lext = [ + /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, + 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78, + ]; + + var dbase = [ + /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, + 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, + 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, + 24577, 0, 0, + ]; + + var dext = [ + /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, + 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, + 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64, + ]; + + module.exports = function inflate_table( + type, + lens, + lens_index, + codes, + table, + table_index, + work, + opts + ) { + var bits = opts.bits; + //here = opts.here; /* table entry for duplication */ + + var len = 0; /* a code's length in bits */ + var sym = 0; /* index of code symbols */ + var min = 0, + max = 0; /* minimum and maximum code lengths */ + var root = 0; /* number of index bits for root table */ + var curr = 0; /* number of index bits for current table */ + var drop = 0; /* code bits to drop for sub-table */ + var left = 0; /* number of prefix codes available */ + var used = 0; /* code entries in table used */ + var huff = 0; /* Huffman code */ + var incr; /* for incrementing code, index */ + var fill; /* index for replicating entries */ + var low; /* low bits for current root entry */ + var mask; /* mask for low root bits */ + var next; /* next available space in table */ + var base = null; /* base value table to use */ + var base_index = 0; + // var shoextra; /* extra bits table to use */ + var end; /* use base and extra for symbol > end */ + var count = new utils.Buf16( MAXBITS + 1 ); //[MAXBITS+1]; /* number of codes of each length */ + var offs = new utils.Buf16( MAXBITS + 1 ); //[MAXBITS+1]; /* offsets in table for each length */ + var extra = null; + var extra_index = 0; + + var here_bits, here_op, here_val; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for ( len = 0; len <= MAXBITS; len++ ) { + count[ len ] = 0; + } + for ( sym = 0; sym < codes; sym++ ) { + count[ lens[ lens_index + sym ] ]++; + } + + /* bound code lengths, force root to be within code lengths */ + root = bits; + for ( max = MAXBITS; max >= 1; max-- ) { + if ( count[ max ] !== 0 ) { + break; + } + } + if ( root > max ) { + root = max; + } + if ( max === 0 ) { + /* no symbols to code at all */ + //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ + //table.bits[opts.table_index] = 1; //here.bits = (var char)1; + //table.val[opts.table_index++] = 0; //here.val = (var short)0; + table[ table_index++ ] = + ( 1 << 24 ) | ( 64 << 16 ) | 0; + + //table.op[opts.table_index] = 64; + //table.bits[opts.table_index] = 1; + //table.val[opts.table_index++] = 0; + table[ table_index++ ] = + ( 1 << 24 ) | ( 64 << 16 ) | 0; + + opts.bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for ( min = 1; min < max; min++ ) { + if ( count[ min ] !== 0 ) { + break; + } + } + if ( root < min ) { + root = min; + } + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for ( len = 1; len <= MAXBITS; len++ ) { + left <<= 1; + left -= count[ len ]; + if ( left < 0 ) { + return -1; + } /* over-subscribed */ + } + if ( left > 0 && ( type === CODES || max !== 1 ) ) { + return -1; /* incomplete set */ + } + + /* generate offsets into symbol table for each length for sorting */ + offs[ 1 ] = 0; + for ( len = 1; len < MAXBITS; len++ ) { + offs[ len + 1 ] = offs[ len ] + count[ len ]; + } + + /* sort symbols by length, by symbol order within each length */ + for ( sym = 0; sym < codes; sym++ ) { + if ( lens[ lens_index + sym ] !== 0 ) { + work[ offs[ lens[ lens_index + sym ] ]++ ] = + sym; + } + } + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + // poor man optimization - use if-else instead of switch, + // to avoid deopts in old v8 + if ( type === CODES ) { + base = extra = work; /* dummy value--not used */ + end = 19; + } else if ( type === LENS ) { + base = lbase; + base_index -= 257; + extra = lext; + extra_index -= 257; + end = 256; + } else { + /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize opts for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = table_index; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = -1; /* trigger new sub-table when len > root */ + used = 1 << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ( + ( type === LENS && used > ENOUGH_LENS ) || + ( type === DISTS && used > ENOUGH_DISTS ) + ) { + return 1; + } + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here_bits = len - drop; + if ( work[ sym ] < end ) { + here_op = 0; + here_val = work[ sym ]; + } else if ( work[ sym ] > end ) { + here_op = extra[ extra_index + work[ sym ] ]; + here_val = base[ base_index + work[ sym ] ]; + } else { + here_op = 32 + 64; /* end of block */ + here_val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1 << ( len - drop ); + fill = 1 << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + table[ next + ( huff >> drop ) + fill ] = + ( here_bits << 24 ) | + ( here_op << 16 ) | + here_val | + 0; + } while ( fill !== 0 ); + + /* backwards increment the len-bit code huff */ + incr = 1 << ( len - 1 ); + while ( huff & incr ) { + incr >>= 1; + } + if ( incr !== 0 ) { + huff &= incr - 1; + huff += incr; + } else { + huff = 0; + } + + /* go to next symbol, update count, len */ + sym++; + if ( --count[ len ] === 0 ) { + if ( len === max ) { + break; + } + len = lens[ lens_index + work[ sym ] ]; + } + + /* create new sub-table if needed */ + if ( len > root && ( huff & mask ) !== low ) { + /* if first time, transition to sub-tables */ + if ( drop === 0 ) { + drop = root; + } + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = 1 << curr; + while ( curr + drop < max ) { + left -= count[ curr + drop ]; + if ( left <= 0 ) { + break; + } + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1 << curr; + if ( + ( type === LENS && used > ENOUGH_LENS ) || + ( type === DISTS && used > ENOUGH_DISTS ) + ) { + return 1; + } + + /* point entry in root table to sub-table */ + low = huff & mask; + /*table.op[low] = curr; + table.bits[low] = root; + table.val[low] = next - opts.table_index;*/ + table[ low ] = + ( root << 24 ) | + ( curr << 16 ) | + ( next - table_index ) | + 0; + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if ( huff !== 0 ) { + //table.op[next + huff] = 64; /* invalid code marker */ + //table.bits[next + huff] = len - drop; + //table.val[next + huff] = 0; + table[ next + huff ] = + ( ( len - drop ) << 24 ) | ( 64 << 16 ) | 0; + } + + /* set return parameters */ + //opts.table_index += used; + opts.bits = root; + return 0; + }; + }, + { '../utils/common': 1 }, + ], + 10: [ + function ( require, module, exports ) { + 'use strict'; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + module.exports = { + 2: 'need dictionary' /* Z_NEED_DICT 2 */, + 1: 'stream end' /* Z_STREAM_END 1 */, + 0: '' /* Z_OK 0 */, + '-1': 'file error' /* Z_ERRNO (-1) */, + '-2': 'stream error' /* Z_STREAM_ERROR (-2) */, + '-3': 'data error' /* Z_DATA_ERROR (-3) */, + '-4': 'insufficient memory' /* Z_MEM_ERROR (-4) */, + '-5': 'buffer error' /* Z_BUF_ERROR (-5) */, + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */, + }; + }, + {}, + ], + 11: [ + function ( require, module, exports ) { + 'use strict'; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + this.next_in = 0; + /* number of bytes available at input */ + this.avail_in = 0; + /* total number of input bytes read so far */ + this.total_in = 0; + /* next output byte should be put there */ + this.output = null; // JS specific, because we have no pointers + this.next_out = 0; + /* remaining free space at output */ + this.avail_out = 0; + /* total number of bytes output so far */ + this.total_out = 0; + /* last error message, NULL if no error */ + this.msg = '' /*Z_NULL*/; + /* not visible by applications */ + this.state = null; + /* best guess about the data type: binary or text */ + this.data_type = 2 /*Z_UNKNOWN*/; + /* adler32 value of the uncompressed data */ + this.adler = 0; + } + + module.exports = ZStream; + }, + {}, + ], + '/lib/inflate.js': [ + function ( require, module, exports ) { + 'use strict'; + + var zlib_inflate = require( './zlib/inflate' ); + var utils = require( './utils/common' ); + var strings = require( './utils/strings' ); + var c = require( './zlib/constants' ); + var msg = require( './zlib/messages' ); + var ZStream = require( './zlib/zstream' ); + var GZheader = require( './zlib/gzheader' ); + + var toString = Object.prototype.toString; + + /** + * class Inflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[inflate]] + * and [[inflateRaw]]. + **/ + + /* internal + * inflate.chunks -> Array + * + * Chunks of output data, if [[Inflate#onData]] not overridden. + **/ + + /** + * Inflate.result -> Uint8Array|Array|String + * + * Uncompressed result, generated by default [[Inflate#onData]] + * and [[Inflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you + * push a chunk with explicit flush (call [[Inflate#push]] with + * `Z_SYNC_FLUSH` param). + **/ + + /** + * Inflate.err -> Number + * + * Error code after inflate finished. 0 (Z_OK) on success. + * Should be checked if broken data possible. + **/ + + /** + * Inflate.msg -> String + * + * Error message, if [[Inflate.err]] != 0 + **/ + + /** + * new Inflate(options) + * - options (Object): zlib inflate options. + * + * Creates new inflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `windowBits` + * - `dictionary` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw inflate + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * By default, when no options set, autodetect deflate/gzip data format via + * wrapper header. + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * var inflate = new pako.Inflate({ level: 3}); + * + * inflate.push(chunk1, false); + * inflate.push(chunk2, true); // true -> last chunk + * + * if (inflate.err) { throw new Error(inflate.err); } + * + * console.log(inflate.result); + * ``` + **/ + function Inflate( options ) { + if ( ! ( this instanceof Inflate ) ) + return new Inflate( options ); + + this.options = utils.assign( + { + chunkSize: 16384, + windowBits: 0, + to: '', + }, + options || {} + ); + + var opt = this.options; + + // Force window size for `raw` data, if not set directly, + // because we have no header for autodetect. + if ( + opt.raw && + opt.windowBits >= 0 && + opt.windowBits < 16 + ) { + opt.windowBits = -opt.windowBits; + if ( opt.windowBits === 0 ) { + opt.windowBits = -15; + } + } + + // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate + if ( + opt.windowBits >= 0 && + opt.windowBits < 16 && + ! ( options && options.windowBits ) + ) { + opt.windowBits += 32; + } + + // Gzip header has no info about windows size, we can do autodetect only + // for deflate. So, if window size not set, force it to max when gzip possible + if ( opt.windowBits > 15 && opt.windowBits < 48 ) { + // bit 3 (16) -> gzipped data + // bit 4 (32) -> autodetect gzip/deflate + if ( ( opt.windowBits & 15 ) === 0 ) { + opt.windowBits |= 15; + } + } + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new ZStream(); + this.strm.avail_out = 0; + + var status = zlib_inflate.inflateInit2( + this.strm, + opt.windowBits + ); + + if ( status !== c.Z_OK ) { + throw new Error( msg[ status ] ); + } + + this.header = new GZheader(); + + zlib_inflate.inflateGetHeader( this.strm, this.header ); + + // Setup dictionary + if ( opt.dictionary ) { + // Convert data if needed + if ( typeof opt.dictionary === 'string' ) { + opt.dictionary = strings.string2buf( + opt.dictionary + ); + } else if ( + toString.call( opt.dictionary ) === + '[object ArrayBuffer]' + ) { + opt.dictionary = new Uint8Array( + opt.dictionary + ); + } + if ( opt.raw ) { + //In raw mode we need to set the dictionary early + status = zlib_inflate.inflateSetDictionary( + this.strm, + opt.dictionary + ); + if ( status !== c.Z_OK ) { + throw new Error( msg[ status ] ); + } + } + } + } + + /** + * Inflate#push(data[, mode]) -> Boolean + * - data (Uint8Array|Array|ArrayBuffer|String): input data + * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. + * + * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with + * new output chunks. Returns `true` on success. The last data block must have + * mode Z_FINISH (or `true`). That will flush internal pending buffers and call + * [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you + * can use mode Z_SYNC_FLUSH, keeping the decompression context. + * + * On fail call [[Inflate#onEnd]] with error code and return false. + * + * We strongly recommend to use `Uint8Array` on input for best speed (output + * format is detected automatically). Also, don't skip last param and always + * use the same type in your code (boolean or number). That will improve JS speed. + * + * For regular `Array`-s make sure all elements are [0..255]. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ + Inflate.prototype.push = function ( data, mode ) { + var strm = this.strm; + var chunkSize = this.options.chunkSize; + var dictionary = this.options.dictionary; + var status, _mode; + var next_out_utf8, tail, utf8str; + + // Flag to properly process Z_BUF_ERROR on testing inflate call + // when we check that all output data was flushed. + var allowBufError = false; + + if ( this.ended ) { + return false; + } + _mode = + mode === ~~mode + ? mode + : mode === true + ? c.Z_FINISH + : c.Z_NO_FLUSH; + + // Convert data if needed + if ( typeof data === 'string' ) { + // Only binary strings can be decompressed on practice + strm.input = strings.binstring2buf( data ); + } else if ( + toString.call( data ) === '[object ArrayBuffer]' + ) { + strm.input = new Uint8Array( data ); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + do { + if ( strm.avail_out === 0 ) { + strm.output = new utils.Buf8( chunkSize ); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + + status = zlib_inflate.inflate( + strm, + c.Z_NO_FLUSH + ); /* no bad return value */ + + if ( status === c.Z_NEED_DICT && dictionary ) { + status = zlib_inflate.inflateSetDictionary( + this.strm, + dictionary + ); + } + + if ( + status === c.Z_BUF_ERROR && + allowBufError === true + ) { + status = c.Z_OK; + allowBufError = false; + } + + if ( + status !== c.Z_STREAM_END && + status !== c.Z_OK + ) { + this.onEnd( status ); + this.ended = true; + return false; + } + + if ( strm.next_out ) { + if ( + strm.avail_out === 0 || + status === c.Z_STREAM_END || + ( strm.avail_in === 0 && + ( _mode === c.Z_FINISH || + _mode === c.Z_SYNC_FLUSH ) ) + ) { + if ( this.options.to === 'string' ) { + next_out_utf8 = strings.utf8border( + strm.output, + strm.next_out + ); + + tail = strm.next_out - next_out_utf8; + utf8str = strings.buf2string( + strm.output, + next_out_utf8 + ); + + // move tail + strm.next_out = tail; + strm.avail_out = chunkSize - tail; + if ( tail ) { + utils.arraySet( + strm.output, + strm.output, + next_out_utf8, + tail, + 0 + ); + } + + this.onData( utf8str ); + } else { + this.onData( + utils.shrinkBuf( + strm.output, + strm.next_out + ) + ); + } + } + } + + // When no more input data, we should check that internal inflate buffers + // are flushed. The only way to do it when avail_out = 0 - run one more + // inflate pass. But if output data not exists, inflate return Z_BUF_ERROR. + // Here we set flag to process this error properly. + // + // NOTE. Deflate does not return error in this case and does not needs such + // logic. + if ( strm.avail_in === 0 && strm.avail_out === 0 ) { + allowBufError = true; + } + } while ( + ( strm.avail_in > 0 || strm.avail_out === 0 ) && + status !== c.Z_STREAM_END + ); + + if ( status === c.Z_STREAM_END ) { + _mode = c.Z_FINISH; + } + + // Finalize on the last chunk. + if ( _mode === c.Z_FINISH ) { + status = zlib_inflate.inflateEnd( this.strm ); + this.onEnd( status ); + this.ended = true; + return status === c.Z_OK; + } + + // callback interim results if Z_SYNC_FLUSH. + if ( _mode === c.Z_SYNC_FLUSH ) { + this.onEnd( c.Z_OK ); + strm.avail_out = 0; + return true; + } + + return true; + }; + + /** + * Inflate#onData(chunk) -> Void + * - chunk (Uint8Array|Array|String): output data. Type of array depends + * on js engine support. When string output requested, each chunk + * will be string. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ + Inflate.prototype.onData = function ( chunk ) { + this.chunks.push( chunk ); + }; + + /** + * Inflate#onEnd(status) -> Void + * - status (Number): inflate status. 0 (Z_OK) on success, + * other if not. + * + * Called either after you tell inflate that the input stream is + * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH) + * or if an error happened. By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ + Inflate.prototype.onEnd = function ( status ) { + // On success - join + if ( status === c.Z_OK ) { + if ( this.options.to === 'string' ) { + // Glue & convert here, until we teach pako to send + // utf8 aligned strings to onData + this.result = this.chunks.join( '' ); + } else { + this.result = utils.flattenChunks( + this.chunks + ); + } + } + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; + }; + + /** + * inflate(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * Decompress `data` with inflate/ungzip and `options`. Autodetect + * format via wrapper header by default. That's why we don't provide + * separate `ungzip` method. + * + * Supported options are: + * + * - windowBits + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) + * , output; + * + * try { + * output = pako.inflate(input); + * } catch (err) + * console.log(err); + * } + * ``` + **/ + function inflate( input, options ) { + var inflator = new Inflate( options ); + + inflator.push( input, true ); + + // That will never happens, if you don't cheat with options :) + if ( inflator.err ) { + throw inflator.msg || msg[ inflator.err ]; + } + + return inflator.result; + } + + /** + * inflateRaw(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * The same as [[inflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ + function inflateRaw( input, options ) { + options = options || {}; + options.raw = true; + return inflate( input, options ); + } + + /** + * ungzip(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * Just shortcut to [[inflate]], because it autodetects format + * by header.content. Done for convenience. + **/ + + exports.Inflate = Inflate; + exports.inflate = inflate; + exports.inflateRaw = inflateRaw; + exports.ungzip = inflate; + }, + { + './utils/common': 1, + './utils/strings': 2, + './zlib/constants': 4, + './zlib/gzheader': 6, + './zlib/inflate': 8, + './zlib/messages': 10, + './zlib/zstream': 11, + }, + ], + }, + {}, + [] + )( '/lib/inflate.js' ); +} ); +/* eslint-enable */ diff --git a/packages/global-styles-ui/src/font-library-modal/lib/lib-font.browser.d.ts b/packages/global-styles-ui/src/font-library-modal/lib/lib-font.browser.d.ts new file mode 100644 index 00000000000000..618e5eea5562a7 --- /dev/null +++ b/packages/global-styles-ui/src/font-library-modal/lib/lib-font.browser.d.ts @@ -0,0 +1,11 @@ +// Type declarations for lib-font.browser.js +export class Font { + constructor( name: string, options?: any ); + opentype: any; + tables: any; + onload?: ( event: { detail: { font: any } } ) => void; + fromDataBuffer( buffer: ArrayBuffer | any, filename: string ): void; + static create( name: string, options?: any ): Font; + static load( url: string, options?: any ): Promise< Font >; + static loadFromArrayBuffer( arrayBuffer: ArrayBuffer, options?: any ): Font; +} diff --git a/packages/edit-site/lib/lib-font.browser.js b/packages/global-styles-ui/src/font-library-modal/lib/lib-font.browser.js similarity index 99% rename from packages/edit-site/lib/lib-font.browser.js rename to packages/global-styles-ui/src/font-library-modal/lib/lib-font.browser.js index a39901c377e42b..db5be2088a3447 100644 --- a/packages/edit-site/lib/lib-font.browser.js +++ b/packages/global-styles-ui/src/font-library-modal/lib/lib-font.browser.js @@ -31,8 +31,8 @@ /* eslint eslint-comments/no-unlimited-disable: 0 */ /* eslint-disable */ // import pako from 'pako'; -import unbrotli from "./unbrotli"; -import GzipDecode from "./inflate"; +import unbrotli from './unbrotli'; +import GzipDecode from './inflate'; let fetchFunction = globalThis.fetch; // if ( ! fetchFunction ) { diff --git a/packages/global-styles-ui/src/font-library-modal/lib/unbrotli.js b/packages/global-styles-ui/src/font-library-modal/lib/unbrotli.js new file mode 100644 index 00000000000000..13fb4f650bfa4f --- /dev/null +++ b/packages/global-styles-ui/src/font-library-modal/lib/unbrotli.js @@ -0,0 +1,2706 @@ +/** + * Credits: + * + * lib-font + * https://github.com/Pomax/lib-font + * https://github.com/Pomax/lib-font/blob/master/lib/unbrotli.js + * + * The MIT License (MIT) + * + * Copyright (c) 2020 pomax@nihongoresources.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint eslint-comments/no-unlimited-disable: 0 */ +/* eslint-disable */ +( function ( f ) { + if ( typeof exports === 'object' && typeof module !== 'undefined' ) { + module.exports = f(); + } else if ( typeof define === 'function' && define.amd ) { + define( [], f ); + } else { + var g; + if ( typeof window !== 'undefined' ) { + g = window; + } else if ( typeof global !== 'undefined' ) { + g = global; + } else if ( typeof self !== 'undefined' ) { + g = self; + } else { + g = this; + } + g.unbrotli = f(); + } +} )( function () { + var define, module, exports; + return ( function () { + function r( e, n, t ) { + function o( i, f ) { + if ( ! n[ i ] ) { + if ( ! e[ i ] ) { + var c = 'function' == typeof require && require; + if ( ! f && c ) return c( i, ! 0 ); + if ( u ) return u( i, ! 0 ); + var a = new Error( "Cannot find module '" + i + "'" ); + throw ( ( a.code = 'MODULE_NOT_FOUND' ), a ); + } + var p = ( n[ i ] = { exports: {} } ); + e[ i ][ 0 ].call( + p.exports, + function ( r ) { + var n = e[ i ][ 1 ][ r ]; + return o( n || r ); + }, + p, + p.exports, + r, + e, + n, + t + ); + } + return n[ i ].exports; + } + for ( + var u = 'function' == typeof require && require, i = 0; + i < t.length; + i++ + ) + o( t[ i ] ); + return o; + } + return r; + } )()( + { + 1: [ + function ( require, module, exports ) { + /* Copyright 2013 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Bit reading helpers +*/ + + var BROTLI_READ_SIZE = 4096; + var BROTLI_IBUF_SIZE = 2 * BROTLI_READ_SIZE + 32; + var BROTLI_IBUF_MASK = 2 * BROTLI_READ_SIZE - 1; + + var kBitMask = new Uint32Array( [ + 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, + 8191, 16383, 32767, 65535, 131071, 262143, 524287, + 1048575, 2097151, 4194303, 8388607, 16777215, + ] ); + + /* Input byte buffer, consist of a ringbuffer and a "slack" region where */ + /* bytes from the start of the ringbuffer are copied. */ + function BrotliBitReader( input ) { + this.buf_ = new Uint8Array( BROTLI_IBUF_SIZE ); + this.input_ = input; /* input callback */ + + this.reset(); + } + + BrotliBitReader.READ_SIZE = BROTLI_READ_SIZE; + BrotliBitReader.IBUF_MASK = BROTLI_IBUF_MASK; + + BrotliBitReader.prototype.reset = function () { + this.buf_ptr_ = 0; /* next input will write here */ + this.val_ = 0; /* pre-fetched bits */ + this.pos_ = 0; /* byte position in stream */ + this.bit_pos_ = 0; /* current bit-reading position in val_ */ + this.bit_end_pos_ = 0; /* bit-reading end position from LSB of val_ */ + this.eos_ = 0; /* input stream is finished */ + + this.readMoreInput(); + for ( var i = 0; i < 4; i++ ) { + this.val_ |= this.buf_[ this.pos_ ] << ( 8 * i ); + ++this.pos_; + } + + return this.bit_end_pos_ > 0; + }; + + /* Fills up the input ringbuffer by calling the input callback. + + Does nothing if there are at least 32 bytes present after current position. + + Returns 0 if either: + - the input callback returned an error, or + - there is no more input and the position is past the end of the stream. + + After encountering the end of the input stream, 32 additional zero bytes are + copied to the ringbuffer, therefore it is safe to call this function after + every 32 bytes of input is read. +*/ + BrotliBitReader.prototype.readMoreInput = function () { + if ( this.bit_end_pos_ > 256 ) { + return; + } else if ( this.eos_ ) { + if ( this.bit_pos_ > this.bit_end_pos_ ) + throw new Error( + 'Unexpected end of input ' + + this.bit_pos_ + + ' ' + + this.bit_end_pos_ + ); + } else { + var dst = this.buf_ptr_; + var bytes_read = this.input_.read( + this.buf_, + dst, + BROTLI_READ_SIZE + ); + if ( bytes_read < 0 ) { + throw new Error( 'Unexpected end of input' ); + } + + if ( bytes_read < BROTLI_READ_SIZE ) { + this.eos_ = 1; + /* Store 32 bytes of zero after the stream end. */ + for ( var p = 0; p < 32; p++ ) + this.buf_[ dst + bytes_read + p ] = 0; + } + + if ( dst === 0 ) { + /* Copy the head of the ringbuffer to the slack region. */ + for ( var p = 0; p < 32; p++ ) + this.buf_[ ( BROTLI_READ_SIZE << 1 ) + p ] = + this.buf_[ p ]; + + this.buf_ptr_ = BROTLI_READ_SIZE; + } else { + this.buf_ptr_ = 0; + } + + this.bit_end_pos_ += bytes_read << 3; + } + }; + + /* Guarantees that there are at least 24 bits in the buffer. */ + BrotliBitReader.prototype.fillBitWindow = function () { + while ( this.bit_pos_ >= 8 ) { + this.val_ >>>= 8; + this.val_ |= + this.buf_[ this.pos_ & BROTLI_IBUF_MASK ] << 24; + ++this.pos_; + this.bit_pos_ = ( this.bit_pos_ - 8 ) >>> 0; + this.bit_end_pos_ = ( this.bit_end_pos_ - 8 ) >>> 0; + } + }; + + /* Reads the specified number of bits from Read Buffer. */ + BrotliBitReader.prototype.readBits = function ( n_bits ) { + if ( 32 - this.bit_pos_ < n_bits ) { + this.fillBitWindow(); + } + + var val = + ( this.val_ >>> this.bit_pos_ ) & + kBitMask[ n_bits ]; + this.bit_pos_ += n_bits; + return val; + }; + + module.exports = BrotliBitReader; + }, + {}, + ], + 2: [ + function ( require, module, exports ) { + /* Copyright 2013 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Lookup table to map the previous two bytes to a context id. + + There are four different context modeling modes defined here: + CONTEXT_LSB6: context id is the least significant 6 bits of the last byte, + CONTEXT_MSB6: context id is the most significant 6 bits of the last byte, + CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text, + CONTEXT_SIGNED: second-order context model tuned for signed integers. + + The context id for the UTF8 context model is calculated as follows. If p1 + and p2 are the previous two bytes, we calcualte the context as + + context = kContextLookup[p1] | kContextLookup[p2 + 256]. + + If the previous two bytes are ASCII characters (i.e. < 128), this will be + equivalent to + + context = 4 * context1(p1) + context2(p2), + + where context1 is based on the previous byte in the following way: + + 0 : non-ASCII control + 1 : \t, \n, \r + 2 : space + 3 : other punctuation + 4 : " ' + 5 : % + 6 : ( < [ { + 7 : ) > ] } + 8 : , ; : + 9 : . + 10 : = + 11 : number + 12 : upper-case vowel + 13 : upper-case consonant + 14 : lower-case vowel + 15 : lower-case consonant + + and context2 is based on the second last byte: + + 0 : control, space + 1 : punctuation + 2 : upper-case letter, number + 3 : lower-case letter + + If the last byte is ASCII, and the second last byte is not (in a valid UTF8 + stream it will be a continuation byte, value between 128 and 191), the + context is the same as if the second last byte was an ASCII control or space. + + If the last byte is a UTF8 lead byte (value >= 192), then the next byte will + be a continuation byte and the context id is 2 or 3 depending on the LSB of + the last byte and to a lesser extent on the second last byte if it is ASCII. + + If the last byte is a UTF8 continuation byte, the second last byte can be: + - continuation byte: the next byte is probably ASCII or lead byte (assuming + 4-byte UTF8 characters are rare) and the context id is 0 or 1. + - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1 + - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3 + + The possible value combinations of the previous two bytes, the range of + context ids and the type of the next byte is summarized in the table below: + + |--------\-----------------------------------------------------------------| + | \ Last byte | + | Second \---------------------------------------------------------------| + | last byte \ ASCII | cont. byte | lead byte | + | \ (0-127) | (128-191) | (192-) | + |=============|===================|=====================|==================| + | ASCII | next: ASCII/lead | not valid | next: cont. | + | (0-127) | context: 4 - 63 | | context: 2 - 3 | + |-------------|-------------------|---------------------|------------------| + | cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. | + | (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 | + |-------------|-------------------|---------------------|------------------| + | lead byte | not valid | next: ASCII/lead | not valid | + | (192-207) | | context: 0 - 1 | | + |-------------|-------------------|---------------------|------------------| + | lead byte | not valid | next: cont. | not valid | + | (208-) | | context: 2 - 3 | | + |-------------|-------------------|---------------------|------------------| + + The context id for the signed context mode is calculated as: + + context = (kContextLookup[512 + p1] << 3) | kContextLookup[512 + p2]. + + For any context modeling modes, the context ids can be calculated by |-ing + together two lookups from one table using context model dependent offsets: + + context = kContextLookup[offset1 + p1] | kContextLookup[offset2 + p2]. + + where offset1 and offset2 are dependent on the context mode. +*/ + + var CONTEXT_LSB6 = 0; + var CONTEXT_MSB6 = 1; + var CONTEXT_UTF8 = 2; + var CONTEXT_SIGNED = 3; + + /* Common context lookup table for all context modes. */ + exports.lookup = new Uint8Array( [ + /* CONTEXT_UTF8, last byte. */ + /* ASCII range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 16, 12, + 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12, + 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, + 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, + 12, 28, 12, 12, 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, + 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, 60, 60, + 60, 60, 60, 24, 12, 28, 12, 0, + /* UTF8 continuation byte range. */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1 /* UTF8 lead byte range. */, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3 /* CONTEXT_UTF8 second last byte. */, + /* ASCII range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, + /* UTF8 continuation byte range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 /* UTF8 lead byte range. */, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2 /* CONTEXT_SIGNED, second last byte. */, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 7, + /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */ + 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, + /* CONTEXT_LSB6, last byte. */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, + /* CONTEXT_MSB6, last byte. */ + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, + 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, + 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, + 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, + 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, + 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, + 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, + 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, + 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, + 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, + 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, + 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, + 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, + 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, + 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, + 62, 62, 62, 62, 63, 63, 63, 63, + /* CONTEXT_{M,L}SB6, second last byte, */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + ] ); + + exports.lookupOffsets = new Uint16Array( [ + /* CONTEXT_LSB6 */ + 1024, 1536 /* CONTEXT_MSB6 */, 1280, + 1536 /* CONTEXT_UTF8 */, 0, 256 /* CONTEXT_SIGNED */, + 768, 512, + ] ); + }, + {}, + ], + 3: [ + function ( require, module, exports ) { + /* Copyright 2013 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + var BrotliInput = require( './streams' ).BrotliInput; + var BrotliOutput = require( './streams' ).BrotliOutput; + var BrotliBitReader = require( './bit_reader' ); + var BrotliDictionary = require( './dictionary' ); + var HuffmanCode = require( './huffman' ).HuffmanCode; + var BrotliBuildHuffmanTable = + require( './huffman' ).BrotliBuildHuffmanTable; + var Context = require( './context' ); + var Prefix = require( './prefix' ); + var Transform = require( './transform' ); + + var kDefaultCodeLength = 8; + var kCodeLengthRepeatCode = 16; + var kNumLiteralCodes = 256; + var kNumInsertAndCopyCodes = 704; + var kNumBlockLengthCodes = 26; + var kLiteralContextBits = 6; + var kDistanceContextBits = 2; + + var HUFFMAN_TABLE_BITS = 8; + var HUFFMAN_TABLE_MASK = 0xff; + /* Maximum possible Huffman table size for an alphabet size of 704, max code + * length 15 and root table bits 8. */ + var HUFFMAN_MAX_TABLE_SIZE = 1080; + + var CODE_LENGTH_CODES = 18; + var kCodeLengthCodeOrder = new Uint8Array( [ + 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, + 14, 15, + ] ); + + var NUM_DISTANCE_SHORT_CODES = 16; + var kDistanceShortCodeIndexOffset = new Uint8Array( [ + 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + ] ); + + var kDistanceShortCodeValueOffset = new Int8Array( [ + 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3, + ] ); + + var kMaxHuffmanTableSize = new Uint16Array( [ + 256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, + 726, 758, 790, 822, 854, 886, 920, 952, 984, 1016, 1048, + 1080, + ] ); + + function DecodeWindowBits( br ) { + var n; + if ( br.readBits( 1 ) === 0 ) { + return 16; + } + + n = br.readBits( 3 ); + if ( n > 0 ) { + return 17 + n; + } + + n = br.readBits( 3 ); + if ( n > 0 ) { + return 8 + n; + } + + return 17; + } + + /* Decodes a number in the range [0..255], by reading 1 - 11 bits. */ + function DecodeVarLenUint8( br ) { + if ( br.readBits( 1 ) ) { + var nbits = br.readBits( 3 ); + if ( nbits === 0 ) { + return 1; + } else { + return br.readBits( nbits ) + ( 1 << nbits ); + } + } + return 0; + } + + function MetaBlockLength() { + this.meta_block_length = 0; + this.input_end = 0; + this.is_uncompressed = 0; + this.is_metadata = false; + } + + function DecodeMetaBlockLength( br ) { + var out = new MetaBlockLength(); + var size_nibbles; + var size_bytes; + var i; + + out.input_end = br.readBits( 1 ); + if ( out.input_end && br.readBits( 1 ) ) { + return out; + } + + size_nibbles = br.readBits( 2 ) + 4; + if ( size_nibbles === 7 ) { + out.is_metadata = true; + + if ( br.readBits( 1 ) !== 0 ) + throw new Error( 'Invalid reserved bit' ); + + size_bytes = br.readBits( 2 ); + if ( size_bytes === 0 ) return out; + + for ( i = 0; i < size_bytes; i++ ) { + var next_byte = br.readBits( 8 ); + if ( + i + 1 === size_bytes && + size_bytes > 1 && + next_byte === 0 + ) + throw new Error( 'Invalid size byte' ); + + out.meta_block_length |= next_byte << ( i * 8 ); + } + } else { + for ( i = 0; i < size_nibbles; ++i ) { + var next_nibble = br.readBits( 4 ); + if ( + i + 1 === size_nibbles && + size_nibbles > 4 && + next_nibble === 0 + ) + throw new Error( 'Invalid size nibble' ); + + out.meta_block_length |= + next_nibble << ( i * 4 ); + } + } + + ++out.meta_block_length; + + if ( ! out.input_end && ! out.is_metadata ) { + out.is_uncompressed = br.readBits( 1 ); + } + + return out; + } + + /* Decodes the next Huffman code from bit-stream. */ + function ReadSymbol( table, index, br ) { + var start_index = index; + + var nbits; + br.fillBitWindow(); + index += + ( br.val_ >>> br.bit_pos_ ) & HUFFMAN_TABLE_MASK; + nbits = table[ index ].bits - HUFFMAN_TABLE_BITS; + if ( nbits > 0 ) { + br.bit_pos_ += HUFFMAN_TABLE_BITS; + index += table[ index ].value; + index += + ( br.val_ >>> br.bit_pos_ ) & + ( ( 1 << nbits ) - 1 ); + } + br.bit_pos_ += table[ index ].bits; + return table[ index ].value; + } + + function ReadHuffmanCodeLengths( + code_length_code_lengths, + num_symbols, + code_lengths, + br + ) { + var symbol = 0; + var prev_code_len = kDefaultCodeLength; + var repeat = 0; + var repeat_code_len = 0; + var space = 32768; + + var table = []; + for ( var i = 0; i < 32; i++ ) + table.push( new HuffmanCode( 0, 0 ) ); + + BrotliBuildHuffmanTable( + table, + 0, + 5, + code_length_code_lengths, + CODE_LENGTH_CODES + ); + + while ( symbol < num_symbols && space > 0 ) { + var p = 0; + var code_len; + + br.readMoreInput(); + br.fillBitWindow(); + p += ( br.val_ >>> br.bit_pos_ ) & 31; + br.bit_pos_ += table[ p ].bits; + code_len = table[ p ].value & 0xff; + if ( code_len < kCodeLengthRepeatCode ) { + repeat = 0; + code_lengths[ symbol++ ] = code_len; + if ( code_len !== 0 ) { + prev_code_len = code_len; + space -= 32768 >> code_len; + } + } else { + var extra_bits = code_len - 14; + var old_repeat; + var repeat_delta; + var new_len = 0; + if ( code_len === kCodeLengthRepeatCode ) { + new_len = prev_code_len; + } + if ( repeat_code_len !== new_len ) { + repeat = 0; + repeat_code_len = new_len; + } + old_repeat = repeat; + if ( repeat > 0 ) { + repeat -= 2; + repeat <<= extra_bits; + } + repeat += br.readBits( extra_bits ) + 3; + repeat_delta = repeat - old_repeat; + if ( symbol + repeat_delta > num_symbols ) { + throw new Error( + '[ReadHuffmanCodeLengths] symbol + repeat_delta > num_symbols' + ); + } + + for ( var x = 0; x < repeat_delta; x++ ) + code_lengths[ symbol + x ] = + repeat_code_len; + + symbol += repeat_delta; + + if ( repeat_code_len !== 0 ) { + space -= + repeat_delta << + ( 15 - repeat_code_len ); + } + } + } + if ( space !== 0 ) { + throw new Error( + '[ReadHuffmanCodeLengths] space = ' + space + ); + } + + for ( ; symbol < num_symbols; symbol++ ) + code_lengths[ symbol ] = 0; + } + + function ReadHuffmanCode( + alphabet_size, + tables, + table, + br + ) { + var table_size = 0; + var simple_code_or_skip; + var code_lengths = new Uint8Array( alphabet_size ); + + br.readMoreInput(); + + /* simple_code_or_skip is used as follows: + 1 for simple code; + 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */ + simple_code_or_skip = br.readBits( 2 ); + if ( simple_code_or_skip === 1 ) { + /* Read symbols, codes & code lengths directly. */ + var i; + var max_bits_counter = alphabet_size - 1; + var max_bits = 0; + var symbols = new Int32Array( 4 ); + var num_symbols = br.readBits( 2 ) + 1; + while ( max_bits_counter ) { + max_bits_counter >>= 1; + ++max_bits; + } + + for ( i = 0; i < num_symbols; ++i ) { + symbols[ i ] = + br.readBits( max_bits ) % alphabet_size; + code_lengths[ symbols[ i ] ] = 2; + } + code_lengths[ symbols[ 0 ] ] = 1; + switch ( num_symbols ) { + case 1: + break; + case 3: + if ( + symbols[ 0 ] === symbols[ 1 ] || + symbols[ 0 ] === symbols[ 2 ] || + symbols[ 1 ] === symbols[ 2 ] + ) { + throw new Error( + '[ReadHuffmanCode] invalid symbols' + ); + } + break; + case 2: + if ( symbols[ 0 ] === symbols[ 1 ] ) { + throw new Error( + '[ReadHuffmanCode] invalid symbols' + ); + } + + code_lengths[ symbols[ 1 ] ] = 1; + break; + case 4: + if ( + symbols[ 0 ] === symbols[ 1 ] || + symbols[ 0 ] === symbols[ 2 ] || + symbols[ 0 ] === symbols[ 3 ] || + symbols[ 1 ] === symbols[ 2 ] || + symbols[ 1 ] === symbols[ 3 ] || + symbols[ 2 ] === symbols[ 3 ] + ) { + throw new Error( + '[ReadHuffmanCode] invalid symbols' + ); + } + + if ( br.readBits( 1 ) ) { + code_lengths[ symbols[ 2 ] ] = 3; + code_lengths[ symbols[ 3 ] ] = 3; + } else { + code_lengths[ symbols[ 0 ] ] = 2; + } + break; + } + } else { + /* Decode Huffman-coded code lengths. */ + var i; + var code_length_code_lengths = new Uint8Array( + CODE_LENGTH_CODES + ); + var space = 32; + var num_codes = 0; + /* Static Huffman code for the code length code lengths */ + var huff = [ + new HuffmanCode( 2, 0 ), + new HuffmanCode( 2, 4 ), + new HuffmanCode( 2, 3 ), + new HuffmanCode( 3, 2 ), + new HuffmanCode( 2, 0 ), + new HuffmanCode( 2, 4 ), + new HuffmanCode( 2, 3 ), + new HuffmanCode( 4, 1 ), + new HuffmanCode( 2, 0 ), + new HuffmanCode( 2, 4 ), + new HuffmanCode( 2, 3 ), + new HuffmanCode( 3, 2 ), + new HuffmanCode( 2, 0 ), + new HuffmanCode( 2, 4 ), + new HuffmanCode( 2, 3 ), + new HuffmanCode( 4, 5 ), + ]; + for ( + i = simple_code_or_skip; + i < CODE_LENGTH_CODES && space > 0; + ++i + ) { + var code_len_idx = kCodeLengthCodeOrder[ i ]; + var p = 0; + var v; + br.fillBitWindow(); + p += ( br.val_ >>> br.bit_pos_ ) & 15; + br.bit_pos_ += huff[ p ].bits; + v = huff[ p ].value; + code_length_code_lengths[ code_len_idx ] = v; + if ( v !== 0 ) { + space -= 32 >> v; + ++num_codes; + } + } + + if ( ! ( num_codes === 1 || space === 0 ) ) + throw new Error( + '[ReadHuffmanCode] invalid num_codes or space' + ); + + ReadHuffmanCodeLengths( + code_length_code_lengths, + alphabet_size, + code_lengths, + br + ); + } + + table_size = BrotliBuildHuffmanTable( + tables, + table, + HUFFMAN_TABLE_BITS, + code_lengths, + alphabet_size + ); + + if ( table_size === 0 ) { + throw new Error( + '[ReadHuffmanCode] BuildHuffmanTable failed: ' + ); + } + + return table_size; + } + + function ReadBlockLength( table, index, br ) { + var code; + var nbits; + code = ReadSymbol( table, index, br ); + nbits = Prefix.kBlockLengthPrefixCode[ code ].nbits; + return ( + Prefix.kBlockLengthPrefixCode[ code ].offset + + br.readBits( nbits ) + ); + } + + function TranslateShortCodes( code, ringbuffer, index ) { + var val; + if ( code < NUM_DISTANCE_SHORT_CODES ) { + index += kDistanceShortCodeIndexOffset[ code ]; + index &= 3; + val = + ringbuffer[ index ] + + kDistanceShortCodeValueOffset[ code ]; + } else { + val = code - NUM_DISTANCE_SHORT_CODES + 1; + } + return val; + } + + function MoveToFront( v, index ) { + var value = v[ index ]; + var i = index; + for ( ; i; --i ) v[ i ] = v[ i - 1 ]; + v[ 0 ] = value; + } + + function InverseMoveToFrontTransform( v, v_len ) { + var mtf = new Uint8Array( 256 ); + var i; + for ( i = 0; i < 256; ++i ) { + mtf[ i ] = i; + } + for ( i = 0; i < v_len; ++i ) { + var index = v[ i ]; + v[ i ] = mtf[ index ]; + if ( index ) MoveToFront( mtf, index ); + } + } + + /* Contains a collection of huffman trees with the same alphabet size. */ + function HuffmanTreeGroup( alphabet_size, num_htrees ) { + this.alphabet_size = alphabet_size; + this.num_htrees = num_htrees; + this.codes = new Array( + num_htrees + + num_htrees * + kMaxHuffmanTableSize[ + ( alphabet_size + 31 ) >>> 5 + ] + ); + this.htrees = new Uint32Array( num_htrees ); + } + + HuffmanTreeGroup.prototype.decode = function ( br ) { + var i; + var table_size; + var next = 0; + for ( i = 0; i < this.num_htrees; ++i ) { + this.htrees[ i ] = next; + table_size = ReadHuffmanCode( + this.alphabet_size, + this.codes, + next, + br + ); + next += table_size; + } + }; + + function DecodeContextMap( context_map_size, br ) { + var out = { num_htrees: null, context_map: null }; + var use_rle_for_zeros; + var max_run_length_prefix = 0; + var table; + var i; + + br.readMoreInput(); + var num_htrees = ( out.num_htrees = + DecodeVarLenUint8( br ) + 1 ); + + var context_map = ( out.context_map = new Uint8Array( + context_map_size + ) ); + if ( num_htrees <= 1 ) { + return out; + } + + use_rle_for_zeros = br.readBits( 1 ); + if ( use_rle_for_zeros ) { + max_run_length_prefix = br.readBits( 4 ) + 1; + } + + table = []; + for ( i = 0; i < HUFFMAN_MAX_TABLE_SIZE; i++ ) { + table[ i ] = new HuffmanCode( 0, 0 ); + } + + ReadHuffmanCode( + num_htrees + max_run_length_prefix, + table, + 0, + br + ); + + for ( i = 0; i < context_map_size; ) { + var code; + + br.readMoreInput(); + code = ReadSymbol( table, 0, br ); + if ( code === 0 ) { + context_map[ i ] = 0; + ++i; + } else if ( code <= max_run_length_prefix ) { + var reps = + 1 + ( 1 << code ) + br.readBits( code ); + while ( --reps ) { + if ( i >= context_map_size ) { + throw new Error( + '[DecodeContextMap] i >= context_map_size' + ); + } + context_map[ i ] = 0; + ++i; + } + } else { + context_map[ i ] = code - max_run_length_prefix; + ++i; + } + } + if ( br.readBits( 1 ) ) { + InverseMoveToFrontTransform( + context_map, + context_map_size + ); + } + + return out; + } + + function DecodeBlockType( + max_block_type, + trees, + tree_type, + block_types, + ringbuffers, + indexes, + br + ) { + var ringbuffer = tree_type * 2; + var index = tree_type; + var type_code = ReadSymbol( + trees, + tree_type * HUFFMAN_MAX_TABLE_SIZE, + br + ); + var block_type; + if ( type_code === 0 ) { + block_type = + ringbuffers[ + ringbuffer + ( indexes[ index ] & 1 ) + ]; + } else if ( type_code === 1 ) { + block_type = + ringbuffers[ + ringbuffer + + ( ( indexes[ index ] - 1 ) & 1 ) + ] + 1; + } else { + block_type = type_code - 2; + } + if ( block_type >= max_block_type ) { + block_type -= max_block_type; + } + block_types[ tree_type ] = block_type; + ringbuffers[ ringbuffer + ( indexes[ index ] & 1 ) ] = + block_type; + ++indexes[ index ]; + } + + function CopyUncompressedBlockToOutput( + output, + len, + pos, + ringbuffer, + ringbuffer_mask, + br + ) { + var rb_size = ringbuffer_mask + 1; + var rb_pos = pos & ringbuffer_mask; + var br_pos = br.pos_ & BrotliBitReader.IBUF_MASK; + var nbytes; + + /* For short lengths copy byte-by-byte */ + if ( + len < 8 || + br.bit_pos_ + ( len << 3 ) < br.bit_end_pos_ + ) { + while ( len-- > 0 ) { + br.readMoreInput(); + ringbuffer[ rb_pos++ ] = br.readBits( 8 ); + if ( rb_pos === rb_size ) { + output.write( ringbuffer, rb_size ); + rb_pos = 0; + } + } + return; + } + + if ( br.bit_end_pos_ < 32 ) { + throw new Error( + '[CopyUncompressedBlockToOutput] br.bit_end_pos_ < 32' + ); + } + + /* Copy remaining 0-4 bytes from br.val_ to ringbuffer. */ + while ( br.bit_pos_ < 32 ) { + ringbuffer[ rb_pos ] = br.val_ >>> br.bit_pos_; + br.bit_pos_ += 8; + ++rb_pos; + --len; + } + + /* Copy remaining bytes from br.buf_ to ringbuffer. */ + nbytes = ( br.bit_end_pos_ - br.bit_pos_ ) >> 3; + if ( br_pos + nbytes > BrotliBitReader.IBUF_MASK ) { + var tail = BrotliBitReader.IBUF_MASK + 1 - br_pos; + for ( var x = 0; x < tail; x++ ) + ringbuffer[ rb_pos + x ] = + br.buf_[ br_pos + x ]; + + nbytes -= tail; + rb_pos += tail; + len -= tail; + br_pos = 0; + } + + for ( var x = 0; x < nbytes; x++ ) + ringbuffer[ rb_pos + x ] = br.buf_[ br_pos + x ]; + + rb_pos += nbytes; + len -= nbytes; + + /* If we wrote past the logical end of the ringbuffer, copy the tail of the + ringbuffer to its beginning and flush the ringbuffer to the output. */ + if ( rb_pos >= rb_size ) { + output.write( ringbuffer, rb_size ); + rb_pos -= rb_size; + for ( var x = 0; x < rb_pos; x++ ) + ringbuffer[ x ] = ringbuffer[ rb_size + x ]; + } + + /* If we have more to copy than the remaining size of the ringbuffer, then we + first fill the ringbuffer from the input and then flush the ringbuffer to + the output */ + while ( rb_pos + len >= rb_size ) { + nbytes = rb_size - rb_pos; + if ( + br.input_.read( ringbuffer, rb_pos, nbytes ) < + nbytes + ) { + throw new Error( + '[CopyUncompressedBlockToOutput] not enough bytes' + ); + } + output.write( ringbuffer, rb_size ); + len -= nbytes; + rb_pos = 0; + } + + /* Copy straight from the input onto the ringbuffer. The ringbuffer will be + flushed to the output at a later time. */ + if ( br.input_.read( ringbuffer, rb_pos, len ) < len ) { + throw new Error( + '[CopyUncompressedBlockToOutput] not enough bytes' + ); + } + + /* Restore the state of the bit reader. */ + br.reset(); + } + + /* Advances the bit reader position to the next byte boundary and verifies + that any skipped bits are set to zero. */ + function JumpToByteBoundary( br ) { + var new_bit_pos = ( br.bit_pos_ + 7 ) & ~7; + var pad_bits = br.readBits( new_bit_pos - br.bit_pos_ ); + return pad_bits == 0; + } + + function BrotliDecompressedSize( buffer ) { + var input = new BrotliInput( buffer ); + var br = new BrotliBitReader( input ); + DecodeWindowBits( br ); + var out = DecodeMetaBlockLength( br ); + return out.meta_block_length; + } + + exports.BrotliDecompressedSize = BrotliDecompressedSize; + + function BrotliDecompressBuffer( buffer, output_size ) { + var input = new BrotliInput( buffer ); + + if ( output_size == null ) { + output_size = BrotliDecompressedSize( buffer ); + } + + var output_buffer = new Uint8Array( output_size ); + var output = new BrotliOutput( output_buffer ); + + BrotliDecompress( input, output ); + + if ( output.pos < output.buffer.length ) { + output.buffer = output.buffer.subarray( + 0, + output.pos + ); + } + + return output.buffer; + } + + exports.BrotliDecompressBuffer = BrotliDecompressBuffer; + + function BrotliDecompress( input, output ) { + var i; + var pos = 0; + var input_end = 0; + var window_bits = 0; + var max_backward_distance; + var max_distance = 0; + var ringbuffer_size; + var ringbuffer_mask; + var ringbuffer; + var ringbuffer_end; + /* This ring buffer holds a few past copy distances that will be used by */ + /* some special distance codes. */ + var dist_rb = [ 16, 15, 11, 4 ]; + var dist_rb_idx = 0; + /* The previous 2 bytes used for context. */ + var prev_byte1 = 0; + var prev_byte2 = 0; + var hgroup = [ + new HuffmanTreeGroup( 0, 0 ), + new HuffmanTreeGroup( 0, 0 ), + new HuffmanTreeGroup( 0, 0 ), + ]; + var block_type_trees; + var block_len_trees; + var br; + + /* We need the slack region for the following reasons: + - always doing two 8-byte copies for fast backward copying + - transforms + - flushing the input ringbuffer when decoding uncompressed blocks */ + var kRingBufferWriteAheadSlack = + 128 + BrotliBitReader.READ_SIZE; + + br = new BrotliBitReader( input ); + + /* Decode window size. */ + window_bits = DecodeWindowBits( br ); + max_backward_distance = ( 1 << window_bits ) - 16; + + ringbuffer_size = 1 << window_bits; + ringbuffer_mask = ringbuffer_size - 1; + ringbuffer = new Uint8Array( + ringbuffer_size + + kRingBufferWriteAheadSlack + + BrotliDictionary.maxDictionaryWordLength + ); + ringbuffer_end = ringbuffer_size; + + block_type_trees = []; + block_len_trees = []; + for ( var x = 0; x < 3 * HUFFMAN_MAX_TABLE_SIZE; x++ ) { + block_type_trees[ x ] = new HuffmanCode( 0, 0 ); + block_len_trees[ x ] = new HuffmanCode( 0, 0 ); + } + + while ( ! input_end ) { + var meta_block_remaining_len = 0; + var is_uncompressed; + var block_length = [ 1 << 28, 1 << 28, 1 << 28 ]; + var block_type = [ 0 ]; + var num_block_types = [ 1, 1, 1 ]; + var block_type_rb = [ 0, 1, 0, 1, 0, 1 ]; + var block_type_rb_index = [ 0 ]; + var distance_postfix_bits; + var num_direct_distance_codes; + var distance_postfix_mask; + var num_distance_codes; + var context_map = null; + var context_modes = null; + var num_literal_htrees; + var dist_context_map = null; + var num_dist_htrees; + var context_offset = 0; + var context_map_slice = null; + var literal_htree_index = 0; + var dist_context_offset = 0; + var dist_context_map_slice = null; + var dist_htree_index = 0; + var context_lookup_offset1 = 0; + var context_lookup_offset2 = 0; + var context_mode; + var htree_command; + + for ( i = 0; i < 3; ++i ) { + hgroup[ i ].codes = null; + hgroup[ i ].htrees = null; + } + + br.readMoreInput(); + + var _out = DecodeMetaBlockLength( br ); + meta_block_remaining_len = _out.meta_block_length; + if ( + pos + meta_block_remaining_len > + output.buffer.length + ) { + /* We need to grow the output buffer to fit the additional data. */ + var tmp = new Uint8Array( + pos + meta_block_remaining_len + ); + tmp.set( output.buffer ); + output.buffer = tmp; + } + input_end = _out.input_end; + is_uncompressed = _out.is_uncompressed; + + if ( _out.is_metadata ) { + JumpToByteBoundary( br ); + + for ( + ; + meta_block_remaining_len > 0; + --meta_block_remaining_len + ) { + br.readMoreInput(); + /* Read one byte and ignore it. */ + br.readBits( 8 ); + } + + continue; + } + + if ( meta_block_remaining_len === 0 ) { + continue; + } + + if ( is_uncompressed ) { + br.bit_pos_ = ( br.bit_pos_ + 7 ) & ~7; + CopyUncompressedBlockToOutput( + output, + meta_block_remaining_len, + pos, + ringbuffer, + ringbuffer_mask, + br + ); + pos += meta_block_remaining_len; + continue; + } + + for ( i = 0; i < 3; ++i ) { + num_block_types[ i ] = + DecodeVarLenUint8( br ) + 1; + if ( num_block_types[ i ] >= 2 ) { + ReadHuffmanCode( + num_block_types[ i ] + 2, + block_type_trees, + i * HUFFMAN_MAX_TABLE_SIZE, + br + ); + ReadHuffmanCode( + kNumBlockLengthCodes, + block_len_trees, + i * HUFFMAN_MAX_TABLE_SIZE, + br + ); + block_length[ i ] = ReadBlockLength( + block_len_trees, + i * HUFFMAN_MAX_TABLE_SIZE, + br + ); + block_type_rb_index[ i ] = 1; + } + } + + br.readMoreInput(); + + distance_postfix_bits = br.readBits( 2 ); + num_direct_distance_codes = + NUM_DISTANCE_SHORT_CODES + + ( br.readBits( 4 ) << distance_postfix_bits ); + distance_postfix_mask = + ( 1 << distance_postfix_bits ) - 1; + num_distance_codes = + num_direct_distance_codes + + ( 48 << distance_postfix_bits ); + context_modes = new Uint8Array( + num_block_types[ 0 ] + ); + + for ( i = 0; i < num_block_types[ 0 ]; ++i ) { + br.readMoreInput(); + context_modes[ i ] = br.readBits( 2 ) << 1; + } + + var _o1 = DecodeContextMap( + num_block_types[ 0 ] << kLiteralContextBits, + br + ); + num_literal_htrees = _o1.num_htrees; + context_map = _o1.context_map; + + var _o2 = DecodeContextMap( + num_block_types[ 2 ] << kDistanceContextBits, + br + ); + num_dist_htrees = _o2.num_htrees; + dist_context_map = _o2.context_map; + + hgroup[ 0 ] = new HuffmanTreeGroup( + kNumLiteralCodes, + num_literal_htrees + ); + hgroup[ 1 ] = new HuffmanTreeGroup( + kNumInsertAndCopyCodes, + num_block_types[ 1 ] + ); + hgroup[ 2 ] = new HuffmanTreeGroup( + num_distance_codes, + num_dist_htrees + ); + + for ( i = 0; i < 3; ++i ) { + hgroup[ i ].decode( br ); + } + + context_map_slice = 0; + dist_context_map_slice = 0; + context_mode = context_modes[ block_type[ 0 ] ]; + context_lookup_offset1 = + Context.lookupOffsets[ context_mode ]; + context_lookup_offset2 = + Context.lookupOffsets[ context_mode + 1 ]; + htree_command = hgroup[ 1 ].htrees[ 0 ]; + + while ( meta_block_remaining_len > 0 ) { + var cmd_code; + var range_idx; + var insert_code; + var copy_code; + var insert_length; + var copy_length; + var distance_code; + var distance; + var context; + var j; + var copy_dst; + + br.readMoreInput(); + + if ( block_length[ 1 ] === 0 ) { + DecodeBlockType( + num_block_types[ 1 ], + block_type_trees, + 1, + block_type, + block_type_rb, + block_type_rb_index, + br + ); + block_length[ 1 ] = ReadBlockLength( + block_len_trees, + HUFFMAN_MAX_TABLE_SIZE, + br + ); + htree_command = + hgroup[ 1 ].htrees[ block_type[ 1 ] ]; + } + --block_length[ 1 ]; + cmd_code = ReadSymbol( + hgroup[ 1 ].codes, + htree_command, + br + ); + range_idx = cmd_code >> 6; + if ( range_idx >= 2 ) { + range_idx -= 2; + distance_code = -1; + } else { + distance_code = 0; + } + insert_code = + Prefix.kInsertRangeLut[ range_idx ] + + ( ( cmd_code >> 3 ) & 7 ); + copy_code = + Prefix.kCopyRangeLut[ range_idx ] + + ( cmd_code & 7 ); + insert_length = + Prefix.kInsertLengthPrefixCode[ + insert_code + ].offset + + br.readBits( + Prefix.kInsertLengthPrefixCode[ + insert_code + ].nbits + ); + copy_length = + Prefix.kCopyLengthPrefixCode[ copy_code ] + .offset + + br.readBits( + Prefix.kCopyLengthPrefixCode[ + copy_code + ].nbits + ); + prev_byte1 = + ringbuffer[ ( pos - 1 ) & ringbuffer_mask ]; + prev_byte2 = + ringbuffer[ ( pos - 2 ) & ringbuffer_mask ]; + for ( j = 0; j < insert_length; ++j ) { + br.readMoreInput(); + + if ( block_length[ 0 ] === 0 ) { + DecodeBlockType( + num_block_types[ 0 ], + block_type_trees, + 0, + block_type, + block_type_rb, + block_type_rb_index, + br + ); + block_length[ 0 ] = ReadBlockLength( + block_len_trees, + 0, + br + ); + context_offset = + block_type[ 0 ] << + kLiteralContextBits; + context_map_slice = context_offset; + context_mode = + context_modes[ block_type[ 0 ] ]; + context_lookup_offset1 = + Context.lookupOffsets[ + context_mode + ]; + context_lookup_offset2 = + Context.lookupOffsets[ + context_mode + 1 + ]; + } + context = + Context.lookup[ + context_lookup_offset1 + prev_byte1 + ] | + Context.lookup[ + context_lookup_offset2 + prev_byte2 + ]; + literal_htree_index = + context_map[ + context_map_slice + context + ]; + --block_length[ 0 ]; + prev_byte2 = prev_byte1; + prev_byte1 = ReadSymbol( + hgroup[ 0 ].codes, + hgroup[ 0 ].htrees[ + literal_htree_index + ], + br + ); + ringbuffer[ pos & ringbuffer_mask ] = + prev_byte1; + if ( + ( pos & ringbuffer_mask ) === + ringbuffer_mask + ) { + output.write( + ringbuffer, + ringbuffer_size + ); + } + ++pos; + } + meta_block_remaining_len -= insert_length; + if ( meta_block_remaining_len <= 0 ) break; + + if ( distance_code < 0 ) { + var context; + + br.readMoreInput(); + if ( block_length[ 2 ] === 0 ) { + DecodeBlockType( + num_block_types[ 2 ], + block_type_trees, + 2, + block_type, + block_type_rb, + block_type_rb_index, + br + ); + block_length[ 2 ] = ReadBlockLength( + block_len_trees, + 2 * HUFFMAN_MAX_TABLE_SIZE, + br + ); + dist_context_offset = + block_type[ 2 ] << + kDistanceContextBits; + dist_context_map_slice = + dist_context_offset; + } + --block_length[ 2 ]; + context = + ( copy_length > 4 + ? 3 + : copy_length - 2 ) & 0xff; + dist_htree_index = + dist_context_map[ + dist_context_map_slice + context + ]; + distance_code = ReadSymbol( + hgroup[ 2 ].codes, + hgroup[ 2 ].htrees[ dist_htree_index ], + br + ); + if ( + distance_code >= + num_direct_distance_codes + ) { + var nbits; + var postfix; + var offset; + distance_code -= + num_direct_distance_codes; + postfix = + distance_code & + distance_postfix_mask; + distance_code >>= distance_postfix_bits; + nbits = ( distance_code >> 1 ) + 1; + offset = + ( ( 2 + ( distance_code & 1 ) ) << + nbits ) - + 4; + distance_code = + num_direct_distance_codes + + ( ( offset + + br.readBits( nbits ) ) << + distance_postfix_bits ) + + postfix; + } + } + + /* Convert the distance code to the actual distance by possibly looking */ + /* up past distnaces from the ringbuffer. */ + distance = TranslateShortCodes( + distance_code, + dist_rb, + dist_rb_idx + ); + if ( distance < 0 ) { + throw new Error( + '[BrotliDecompress] invalid distance' + ); + } + + if ( + pos < max_backward_distance && + max_distance !== max_backward_distance + ) { + max_distance = pos; + } else { + max_distance = max_backward_distance; + } + + copy_dst = pos & ringbuffer_mask; + + if ( distance > max_distance ) { + if ( + copy_length >= + BrotliDictionary.minDictionaryWordLength && + copy_length <= + BrotliDictionary.maxDictionaryWordLength + ) { + var offset = + BrotliDictionary.offsetsByLength[ + copy_length + ]; + var word_id = + distance - max_distance - 1; + var shift = + BrotliDictionary.sizeBitsByLength[ + copy_length + ]; + var mask = ( 1 << shift ) - 1; + var word_idx = word_id & mask; + var transform_idx = word_id >> shift; + offset += word_idx * copy_length; + if ( + transform_idx < + Transform.kNumTransforms + ) { + var len = + Transform.transformDictionaryWord( + ringbuffer, + copy_dst, + offset, + copy_length, + transform_idx + ); + copy_dst += len; + pos += len; + meta_block_remaining_len -= len; + if ( copy_dst >= ringbuffer_end ) { + output.write( + ringbuffer, + ringbuffer_size + ); + + for ( + var _x = 0; + _x < + copy_dst - ringbuffer_end; + _x++ + ) + ringbuffer[ _x ] = + ringbuffer[ + ringbuffer_end + _x + ]; + } + } else { + throw new Error( + 'Invalid backward reference. pos: ' + + pos + + ' distance: ' + + distance + + ' len: ' + + copy_length + + ' bytes left: ' + + meta_block_remaining_len + ); + } + } else { + throw new Error( + 'Invalid backward reference. pos: ' + + pos + + ' distance: ' + + distance + + ' len: ' + + copy_length + + ' bytes left: ' + + meta_block_remaining_len + ); + } + } else { + if ( distance_code > 0 ) { + dist_rb[ dist_rb_idx & 3 ] = distance; + ++dist_rb_idx; + } + + if ( + copy_length > meta_block_remaining_len + ) { + throw new Error( + 'Invalid backward reference. pos: ' + + pos + + ' distance: ' + + distance + + ' len: ' + + copy_length + + ' bytes left: ' + + meta_block_remaining_len + ); + } + + for ( j = 0; j < copy_length; ++j ) { + ringbuffer[ pos & ringbuffer_mask ] = + ringbuffer[ + ( pos - distance ) & + ringbuffer_mask + ]; + if ( + ( pos & ringbuffer_mask ) === + ringbuffer_mask + ) { + output.write( + ringbuffer, + ringbuffer_size + ); + } + ++pos; + --meta_block_remaining_len; + } + } + + /* When we get here, we must have inserted at least one literal and */ + /* made a copy of at least length two, therefore accessing the last 2 */ + /* bytes is valid. */ + prev_byte1 = + ringbuffer[ ( pos - 1 ) & ringbuffer_mask ]; + prev_byte2 = + ringbuffer[ ( pos - 2 ) & ringbuffer_mask ]; + } + + /* Protect pos from overflow, wrap it around at every GB of input data */ + pos &= 0x3fffffff; + } + + output.write( ringbuffer, pos & ringbuffer_mask ); + } + + exports.BrotliDecompress = BrotliDecompress; + + BrotliDictionary.init(); + }, + { + './bit_reader': 1, + './context': 2, + './dictionary': 6, + './huffman': 7, + './prefix': 9, + './streams': 10, + './transform': 11, + }, + ], + 4: [ + function ( require, module, exports ) { + var base64 = require( 'base64-js' ); + //var fs = require('fs'); + + /** + * The normal dictionary-data.js is quite large, which makes it + * unsuitable for browser usage. In order to make it smaller, + * we read dictionary.bin, which is a compressed version of + * the dictionary, and on initial load, Brotli decompresses + * it's own dictionary. 😜 + */ + exports.init = function () { + var BrotliDecompressBuffer = + require( './decode' ).BrotliDecompressBuffer; + var compressed = base64.toByteArray( + require( './dictionary.bin.js' ) + ); + return BrotliDecompressBuffer( compressed ); + }; + }, + { './decode': 3, './dictionary.bin.js': 5, 'base64-js': 8 }, + ], + 5: [ + function ( require, module, exports ) { + module.exports = + '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'; + }, + {}, + ], + 6: [ + function ( require, module, exports ) { + /* Copyright 2013 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Collection of static dictionary words. +*/ + + var data = require( './dictionary-browser' ); + exports.init = function () { + exports.dictionary = data.init(); + }; + + exports.offsetsByLength = new Uint32Array( [ + 0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, 53248, + 63488, 74752, 87040, 93696, 100864, 104704, 106752, + 108928, 113536, 115968, 118528, 119872, 121280, 122016, + ] ); + + exports.sizeBitsByLength = new Uint8Array( [ + 0, 0, 0, 0, 10, 10, 11, 11, 10, 10, 10, 10, 10, 9, 9, 8, + 7, 7, 8, 7, 7, 6, 6, 5, 5, + ] ); + + exports.minDictionaryWordLength = 4; + exports.maxDictionaryWordLength = 24; + }, + { './dictionary-browser': 4 }, + ], + 7: [ + function ( require, module, exports ) { + function HuffmanCode( bits, value ) { + this.bits = + bits; /* number of bits used for this symbol */ + this.value = value; /* symbol value or table offset */ + } + + exports.HuffmanCode = HuffmanCode; + + var MAX_LENGTH = 15; + + /* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the + bit-wise reversal of the len least significant bits of key. */ + function GetNextKey( key, len ) { + var step = 1 << ( len - 1 ); + while ( key & step ) { + step >>= 1; + } + return ( key & ( step - 1 ) ) + step; + } + + /* Stores code in table[0], table[step], table[2*step], ..., table[end] */ + /* Assumes that end is an integer multiple of step */ + function ReplicateValue( table, i, step, end, code ) { + do { + end -= step; + table[ i + end ] = new HuffmanCode( + code.bits, + code.value + ); + } while ( end > 0 ); + } + + /* Returns the table width of the next 2nd level table. count is the histogram + of bit lengths for the remaining symbols, len is the code length of the next + processed symbol */ + function NextTableBitSize( count, len, root_bits ) { + var left = 1 << ( len - root_bits ); + while ( len < MAX_LENGTH ) { + left -= count[ len ]; + if ( left <= 0 ) break; + ++len; + left <<= 1; + } + return len - root_bits; + } + + exports.BrotliBuildHuffmanTable = function ( + root_table, + table, + root_bits, + code_lengths, + code_lengths_size + ) { + var start_table = table; + var code; /* current table entry */ + var len; /* current code length */ + var symbol; /* symbol index in original or sorted table */ + var key; /* reversed prefix code */ + var step; /* step size to replicate values in current table */ + var low; /* low bits for current root entry */ + var mask; /* mask for low bits */ + var table_bits; /* key length of current table */ + var table_size; /* size of current table */ + var total_size; /* sum of root table size and 2nd level table sizes */ + var sorted; /* symbols sorted by code length */ + var count = new Int32Array( + MAX_LENGTH + 1 + ); /* number of codes of each length */ + var offset = new Int32Array( + MAX_LENGTH + 1 + ); /* offsets in sorted table for each length */ + + sorted = new Int32Array( code_lengths_size ); + + /* build histogram of code lengths */ + for ( + symbol = 0; + symbol < code_lengths_size; + symbol++ + ) { + count[ code_lengths[ symbol ] ]++; + } + + /* generate offsets into sorted symbol table by code length */ + offset[ 1 ] = 0; + for ( len = 1; len < MAX_LENGTH; len++ ) { + offset[ len + 1 ] = offset[ len ] + count[ len ]; + } + + /* sort symbols by length, by symbol order within each length */ + for ( + symbol = 0; + symbol < code_lengths_size; + symbol++ + ) { + if ( code_lengths[ symbol ] !== 0 ) { + sorted[ offset[ code_lengths[ symbol ] ]++ ] = + symbol; + } + } + + table_bits = root_bits; + table_size = 1 << table_bits; + total_size = table_size; + + /* special case code with only one value */ + if ( offset[ MAX_LENGTH ] === 1 ) { + for ( key = 0; key < total_size; ++key ) { + root_table[ table + key ] = new HuffmanCode( + 0, + sorted[ 0 ] & 0xffff + ); + } + + return total_size; + } + + /* fill in root table */ + key = 0; + symbol = 0; + for ( + len = 1, step = 2; + len <= root_bits; + ++len, step <<= 1 + ) { + for ( ; count[ len ] > 0; --count[ len ] ) { + code = new HuffmanCode( + len & 0xff, + sorted[ symbol++ ] & 0xffff + ); + ReplicateValue( + root_table, + table + key, + step, + table_size, + code + ); + key = GetNextKey( key, len ); + } + } + + /* fill in 2nd level tables and add pointers to root table */ + mask = total_size - 1; + low = -1; + for ( + len = root_bits + 1, step = 2; + len <= MAX_LENGTH; + ++len, step <<= 1 + ) { + for ( ; count[ len ] > 0; --count[ len ] ) { + if ( ( key & mask ) !== low ) { + table += table_size; + table_bits = NextTableBitSize( + count, + len, + root_bits + ); + table_size = 1 << table_bits; + total_size += table_size; + low = key & mask; + root_table[ start_table + low ] = + new HuffmanCode( + ( table_bits + root_bits ) & 0xff, + ( table - start_table - low ) & + 0xffff + ); + } + code = new HuffmanCode( + ( len - root_bits ) & 0xff, + sorted[ symbol++ ] & 0xffff + ); + ReplicateValue( + root_table, + table + ( key >> root_bits ), + step, + table_size, + code + ); + key = GetNextKey( key, len ); + } + } + + return total_size; + }; + }, + {}, + ], + 8: [ + function ( require, module, exports ) { + 'use strict'; + + exports.byteLength = byteLength; + exports.toByteArray = toByteArray; + exports.fromByteArray = fromByteArray; + + var lookup = []; + var revLookup = []; + var Arr = + typeof Uint8Array !== 'undefined' ? Uint8Array : Array; + + var code = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + for ( var i = 0, len = code.length; i < len; ++i ) { + lookup[ i ] = code[ i ]; + revLookup[ code.charCodeAt( i ) ] = i; + } + + // Support decoding URL-safe base64 strings, as Node.js does. + // See: https://en.wikipedia.org/wiki/Base64#URL_applications + revLookup[ '-'.charCodeAt( 0 ) ] = 62; + revLookup[ '_'.charCodeAt( 0 ) ] = 63; + + function getLens( b64 ) { + var len = b64.length; + + if ( len % 4 > 0 ) { + throw new Error( + 'Invalid string. Length must be a multiple of 4' + ); + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf( '=' ); + if ( validLen === -1 ) validLen = len; + + var placeHoldersLen = + validLen === len ? 0 : 4 - ( validLen % 4 ); + + return [ validLen, placeHoldersLen ]; + } + + // base64 is 4/3 + up to two characters of the original data + function byteLength( b64 ) { + var lens = getLens( b64 ); + var validLen = lens[ 0 ]; + var placeHoldersLen = lens[ 1 ]; + return ( + ( ( validLen + placeHoldersLen ) * 3 ) / 4 - + placeHoldersLen + ); + } + + function _byteLength( b64, validLen, placeHoldersLen ) { + return ( + ( ( validLen + placeHoldersLen ) * 3 ) / 4 - + placeHoldersLen + ); + } + + function toByteArray( b64 ) { + var tmp; + var lens = getLens( b64 ); + var validLen = lens[ 0 ]; + var placeHoldersLen = lens[ 1 ]; + + var arr = new Arr( + _byteLength( b64, validLen, placeHoldersLen ) + ); + + var curByte = 0; + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 ? validLen - 4 : validLen; + + for ( var i = 0; i < len; i += 4 ) { + tmp = + ( revLookup[ b64.charCodeAt( i ) ] << 18 ) | + ( revLookup[ b64.charCodeAt( i + 1 ) ] << 12 ) | + ( revLookup[ b64.charCodeAt( i + 2 ) ] << 6 ) | + revLookup[ b64.charCodeAt( i + 3 ) ]; + arr[ curByte++ ] = ( tmp >> 16 ) & 0xff; + arr[ curByte++ ] = ( tmp >> 8 ) & 0xff; + arr[ curByte++ ] = tmp & 0xff; + } + + if ( placeHoldersLen === 2 ) { + tmp = + ( revLookup[ b64.charCodeAt( i ) ] << 2 ) | + ( revLookup[ b64.charCodeAt( i + 1 ) ] >> 4 ); + arr[ curByte++ ] = tmp & 0xff; + } + + if ( placeHoldersLen === 1 ) { + tmp = + ( revLookup[ b64.charCodeAt( i ) ] << 10 ) | + ( revLookup[ b64.charCodeAt( i + 1 ) ] << 4 ) | + ( revLookup[ b64.charCodeAt( i + 2 ) ] >> 2 ); + arr[ curByte++ ] = ( tmp >> 8 ) & 0xff; + arr[ curByte++ ] = tmp & 0xff; + } + + return arr; + } + + function tripletToBase64( num ) { + return ( + lookup[ ( num >> 18 ) & 0x3f ] + + lookup[ ( num >> 12 ) & 0x3f ] + + lookup[ ( num >> 6 ) & 0x3f ] + + lookup[ num & 0x3f ] + ); + } + + function encodeChunk( uint8, start, end ) { + var tmp; + var output = []; + for ( var i = start; i < end; i += 3 ) { + tmp = + ( ( uint8[ i ] << 16 ) & 0xff0000 ) + + ( ( uint8[ i + 1 ] << 8 ) & 0xff00 ) + + ( uint8[ i + 2 ] & 0xff ); + output.push( tripletToBase64( tmp ) ); + } + return output.join( '' ); + } + + function fromByteArray( uint8 ) { + var tmp; + var len = uint8.length; + var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + var parts = []; + var maxChunkLength = 16383; // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for ( + var i = 0, len2 = len - extraBytes; + i < len2; + i += maxChunkLength + ) { + parts.push( + encodeChunk( + uint8, + i, + i + maxChunkLength > len2 + ? len2 + : i + maxChunkLength + ) + ); + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if ( extraBytes === 1 ) { + tmp = uint8[ len - 1 ]; + parts.push( + lookup[ tmp >> 2 ] + + lookup[ ( tmp << 4 ) & 0x3f ] + + '==' + ); + } else if ( extraBytes === 2 ) { + tmp = ( uint8[ len - 2 ] << 8 ) + uint8[ len - 1 ]; + parts.push( + lookup[ tmp >> 10 ] + + lookup[ ( tmp >> 4 ) & 0x3f ] + + lookup[ ( tmp << 2 ) & 0x3f ] + + '=' + ); + } + + return parts.join( '' ); + } + }, + {}, + ], + 9: [ + function ( require, module, exports ) { + /* Copyright 2013 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Lookup tables to map prefix codes to value ranges. This is used during + decoding of the block lengths, literal insertion lengths and copy lengths. +*/ + + /* Represents the range of values belonging to a prefix code: */ + /* [offset, offset + 2^nbits) */ + function PrefixCodeRange( offset, nbits ) { + this.offset = offset; + this.nbits = nbits; + } + + exports.kBlockLengthPrefixCode = [ + new PrefixCodeRange( 1, 2 ), + new PrefixCodeRange( 5, 2 ), + new PrefixCodeRange( 9, 2 ), + new PrefixCodeRange( 13, 2 ), + new PrefixCodeRange( 17, 3 ), + new PrefixCodeRange( 25, 3 ), + new PrefixCodeRange( 33, 3 ), + new PrefixCodeRange( 41, 3 ), + new PrefixCodeRange( 49, 4 ), + new PrefixCodeRange( 65, 4 ), + new PrefixCodeRange( 81, 4 ), + new PrefixCodeRange( 97, 4 ), + new PrefixCodeRange( 113, 5 ), + new PrefixCodeRange( 145, 5 ), + new PrefixCodeRange( 177, 5 ), + new PrefixCodeRange( 209, 5 ), + new PrefixCodeRange( 241, 6 ), + new PrefixCodeRange( 305, 6 ), + new PrefixCodeRange( 369, 7 ), + new PrefixCodeRange( 497, 8 ), + new PrefixCodeRange( 753, 9 ), + new PrefixCodeRange( 1265, 10 ), + new PrefixCodeRange( 2289, 11 ), + new PrefixCodeRange( 4337, 12 ), + new PrefixCodeRange( 8433, 13 ), + new PrefixCodeRange( 16625, 24 ), + ]; + + exports.kInsertLengthPrefixCode = [ + new PrefixCodeRange( 0, 0 ), + new PrefixCodeRange( 1, 0 ), + new PrefixCodeRange( 2, 0 ), + new PrefixCodeRange( 3, 0 ), + new PrefixCodeRange( 4, 0 ), + new PrefixCodeRange( 5, 0 ), + new PrefixCodeRange( 6, 1 ), + new PrefixCodeRange( 8, 1 ), + new PrefixCodeRange( 10, 2 ), + new PrefixCodeRange( 14, 2 ), + new PrefixCodeRange( 18, 3 ), + new PrefixCodeRange( 26, 3 ), + new PrefixCodeRange( 34, 4 ), + new PrefixCodeRange( 50, 4 ), + new PrefixCodeRange( 66, 5 ), + new PrefixCodeRange( 98, 5 ), + new PrefixCodeRange( 130, 6 ), + new PrefixCodeRange( 194, 7 ), + new PrefixCodeRange( 322, 8 ), + new PrefixCodeRange( 578, 9 ), + new PrefixCodeRange( 1090, 10 ), + new PrefixCodeRange( 2114, 12 ), + new PrefixCodeRange( 6210, 14 ), + new PrefixCodeRange( 22594, 24 ), + ]; + + exports.kCopyLengthPrefixCode = [ + new PrefixCodeRange( 2, 0 ), + new PrefixCodeRange( 3, 0 ), + new PrefixCodeRange( 4, 0 ), + new PrefixCodeRange( 5, 0 ), + new PrefixCodeRange( 6, 0 ), + new PrefixCodeRange( 7, 0 ), + new PrefixCodeRange( 8, 0 ), + new PrefixCodeRange( 9, 0 ), + new PrefixCodeRange( 10, 1 ), + new PrefixCodeRange( 12, 1 ), + new PrefixCodeRange( 14, 2 ), + new PrefixCodeRange( 18, 2 ), + new PrefixCodeRange( 22, 3 ), + new PrefixCodeRange( 30, 3 ), + new PrefixCodeRange( 38, 4 ), + new PrefixCodeRange( 54, 4 ), + new PrefixCodeRange( 70, 5 ), + new PrefixCodeRange( 102, 5 ), + new PrefixCodeRange( 134, 6 ), + new PrefixCodeRange( 198, 7 ), + new PrefixCodeRange( 326, 8 ), + new PrefixCodeRange( 582, 9 ), + new PrefixCodeRange( 1094, 10 ), + new PrefixCodeRange( 2118, 24 ), + ]; + + exports.kInsertRangeLut = [ 0, 0, 8, 8, 0, 16, 8, 16, 16 ]; + + exports.kCopyRangeLut = [ 0, 8, 0, 8, 16, 0, 16, 8, 16 ]; + }, + {}, + ], + 10: [ + function ( require, module, exports ) { + function BrotliInput( buffer ) { + this.buffer = buffer; + this.pos = 0; + } + + BrotliInput.prototype.read = function ( buf, i, count ) { + if ( this.pos + count > this.buffer.length ) { + count = this.buffer.length - this.pos; + } + + for ( var p = 0; p < count; p++ ) + buf[ i + p ] = this.buffer[ this.pos + p ]; + + this.pos += count; + return count; + }; + + exports.BrotliInput = BrotliInput; + + function BrotliOutput( buf ) { + this.buffer = buf; + this.pos = 0; + } + + BrotliOutput.prototype.write = function ( buf, count ) { + if ( this.pos + count > this.buffer.length ) + throw new Error( + 'Output buffer is not large enough' + ); + + this.buffer.set( buf.subarray( 0, count ), this.pos ); + this.pos += count; + return count; + }; + + exports.BrotliOutput = BrotliOutput; + }, + {}, + ], + 11: [ + function ( require, module, exports ) { + /* Copyright 2013 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Transformations on dictionary words. +*/ + + var BrotliDictionary = require( './dictionary' ); + + var kIdentity = 0; + var kOmitLast1 = 1; + var kOmitLast2 = 2; + var kOmitLast3 = 3; + var kOmitLast4 = 4; + var kOmitLast5 = 5; + var kOmitLast6 = 6; + var kOmitLast7 = 7; + var kOmitLast8 = 8; + var kOmitLast9 = 9; + var kUppercaseFirst = 10; + var kUppercaseAll = 11; + var kOmitFirst1 = 12; + var kOmitFirst2 = 13; + var kOmitFirst3 = 14; + var kOmitFirst4 = 15; + var kOmitFirst5 = 16; + var kOmitFirst6 = 17; + var kOmitFirst7 = 18; + var kOmitFirst8 = 19; + var kOmitFirst9 = 20; + + function Transform( prefix, transform, suffix ) { + this.prefix = new Uint8Array( prefix.length ); + this.transform = transform; + this.suffix = new Uint8Array( suffix.length ); + + for ( var i = 0; i < prefix.length; i++ ) + this.prefix[ i ] = prefix.charCodeAt( i ); + + for ( var i = 0; i < suffix.length; i++ ) + this.suffix[ i ] = suffix.charCodeAt( i ); + } + + var kTransforms = [ + new Transform( '', kIdentity, '' ), + new Transform( '', kIdentity, ' ' ), + new Transform( ' ', kIdentity, ' ' ), + new Transform( '', kOmitFirst1, '' ), + new Transform( '', kUppercaseFirst, ' ' ), + new Transform( '', kIdentity, ' the ' ), + new Transform( ' ', kIdentity, '' ), + new Transform( 's ', kIdentity, ' ' ), + new Transform( '', kIdentity, ' of ' ), + new Transform( '', kUppercaseFirst, '' ), + new Transform( '', kIdentity, ' and ' ), + new Transform( '', kOmitFirst2, '' ), + new Transform( '', kOmitLast1, '' ), + new Transform( ', ', kIdentity, ' ' ), + new Transform( '', kIdentity, ', ' ), + new Transform( ' ', kUppercaseFirst, ' ' ), + new Transform( '', kIdentity, ' in ' ), + new Transform( '', kIdentity, ' to ' ), + new Transform( 'e ', kIdentity, ' ' ), + new Transform( '', kIdentity, '"' ), + new Transform( '', kIdentity, '.' ), + new Transform( '', kIdentity, '">' ), + new Transform( '', kIdentity, '\n' ), + new Transform( '', kOmitLast3, '' ), + new Transform( '', kIdentity, ']' ), + new Transform( '', kIdentity, ' for ' ), + new Transform( '', kOmitFirst3, '' ), + new Transform( '', kOmitLast2, '' ), + new Transform( '', kIdentity, ' a ' ), + new Transform( '', kIdentity, ' that ' ), + new Transform( ' ', kUppercaseFirst, '' ), + new Transform( '', kIdentity, '. ' ), + new Transform( '.', kIdentity, '' ), + new Transform( ' ', kIdentity, ', ' ), + new Transform( '', kOmitFirst4, '' ), + new Transform( '', kIdentity, ' with ' ), + new Transform( '', kIdentity, "'" ), + new Transform( '', kIdentity, ' from ' ), + new Transform( '', kIdentity, ' by ' ), + new Transform( '', kOmitFirst5, '' ), + new Transform( '', kOmitFirst6, '' ), + new Transform( ' the ', kIdentity, '' ), + new Transform( '', kOmitLast4, '' ), + new Transform( '', kIdentity, '. The ' ), + new Transform( '', kUppercaseAll, '' ), + new Transform( '', kIdentity, ' on ' ), + new Transform( '', kIdentity, ' as ' ), + new Transform( '', kIdentity, ' is ' ), + new Transform( '', kOmitLast7, '' ), + new Transform( '', kOmitLast1, 'ing ' ), + new Transform( '', kIdentity, '\n\t' ), + new Transform( '', kIdentity, ':' ), + new Transform( ' ', kIdentity, '. ' ), + new Transform( '', kIdentity, 'ed ' ), + new Transform( '', kOmitFirst9, '' ), + new Transform( '', kOmitFirst7, '' ), + new Transform( '', kOmitLast6, '' ), + new Transform( '', kIdentity, '(' ), + new Transform( '', kUppercaseFirst, ', ' ), + new Transform( '', kOmitLast8, '' ), + new Transform( '', kIdentity, ' at ' ), + new Transform( '', kIdentity, 'ly ' ), + new Transform( ' the ', kIdentity, ' of ' ), + new Transform( '', kOmitLast5, '' ), + new Transform( '', kOmitLast9, '' ), + new Transform( ' ', kUppercaseFirst, ', ' ), + new Transform( '', kUppercaseFirst, '"' ), + new Transform( '.', kIdentity, '(' ), + new Transform( '', kUppercaseAll, ' ' ), + new Transform( '', kUppercaseFirst, '">' ), + new Transform( '', kIdentity, '="' ), + new Transform( ' ', kIdentity, '.' ), + new Transform( '.com/', kIdentity, '' ), + new Transform( ' the ', kIdentity, ' of the ' ), + new Transform( '', kUppercaseFirst, "'" ), + new Transform( '', kIdentity, '. This ' ), + new Transform( '', kIdentity, ',' ), + new Transform( '.', kIdentity, ' ' ), + new Transform( '', kUppercaseFirst, '(' ), + new Transform( '', kUppercaseFirst, '.' ), + new Transform( '', kIdentity, ' not ' ), + new Transform( ' ', kIdentity, '="' ), + new Transform( '', kIdentity, 'er ' ), + new Transform( ' ', kUppercaseAll, ' ' ), + new Transform( '', kIdentity, 'al ' ), + new Transform( ' ', kUppercaseAll, '' ), + new Transform( '', kIdentity, "='" ), + new Transform( '', kUppercaseAll, '"' ), + new Transform( '', kUppercaseFirst, '. ' ), + new Transform( ' ', kIdentity, '(' ), + new Transform( '', kIdentity, 'ful ' ), + new Transform( ' ', kUppercaseFirst, '. ' ), + new Transform( '', kIdentity, 'ive ' ), + new Transform( '', kIdentity, 'less ' ), + new Transform( '', kUppercaseAll, "'" ), + new Transform( '', kIdentity, 'est ' ), + new Transform( ' ', kUppercaseFirst, '.' ), + new Transform( '', kUppercaseAll, '">' ), + new Transform( ' ', kIdentity, "='" ), + new Transform( '', kUppercaseFirst, ',' ), + new Transform( '', kIdentity, 'ize ' ), + new Transform( '', kUppercaseAll, '.' ), + new Transform( '\xc2\xa0', kIdentity, '' ), + new Transform( ' ', kIdentity, ',' ), + new Transform( '', kUppercaseFirst, '="' ), + new Transform( '', kUppercaseAll, '="' ), + new Transform( '', kIdentity, 'ous ' ), + new Transform( '', kUppercaseAll, ', ' ), + new Transform( '', kUppercaseFirst, "='" ), + new Transform( ' ', kUppercaseFirst, ',' ), + new Transform( ' ', kUppercaseAll, '="' ), + new Transform( ' ', kUppercaseAll, ', ' ), + new Transform( '', kUppercaseAll, ',' ), + new Transform( '', kUppercaseAll, '(' ), + new Transform( '', kUppercaseAll, '. ' ), + new Transform( ' ', kUppercaseAll, '.' ), + new Transform( '', kUppercaseAll, "='" ), + new Transform( ' ', kUppercaseAll, '. ' ), + new Transform( ' ', kUppercaseFirst, '="' ), + new Transform( ' ', kUppercaseAll, "='" ), + new Transform( ' ', kUppercaseFirst, "='" ), + ]; + + exports.kTransforms = kTransforms; + exports.kNumTransforms = kTransforms.length; + + function ToUpperCase( p, i ) { + if ( p[ i ] < 0xc0 ) { + if ( p[ i ] >= 97 && p[ i ] <= 122 ) { + p[ i ] ^= 32; + } + return 1; + } + + /* An overly simplified uppercasing model for utf-8. */ + if ( p[ i ] < 0xe0 ) { + p[ i + 1 ] ^= 32; + return 2; + } + + /* An arbitrary transform for three byte characters. */ + p[ i + 2 ] ^= 5; + return 3; + } + + exports.transformDictionaryWord = function ( + dst, + idx, + word, + len, + transform + ) { + var prefix = kTransforms[ transform ].prefix; + var suffix = kTransforms[ transform ].suffix; + var t = kTransforms[ transform ].transform; + var skip = + t < kOmitFirst1 ? 0 : t - ( kOmitFirst1 - 1 ); + var i = 0; + var start_idx = idx; + var uppercase; + + if ( skip > len ) { + skip = len; + } + + var prefix_pos = 0; + while ( prefix_pos < prefix.length ) { + dst[ idx++ ] = prefix[ prefix_pos++ ]; + } + + word += skip; + len -= skip; + + if ( t <= kOmitLast9 ) { + len -= t; + } + + for ( i = 0; i < len; i++ ) { + dst[ idx++ ] = + BrotliDictionary.dictionary[ word + i ]; + } + + uppercase = idx - len; + + if ( t === kUppercaseFirst ) { + ToUpperCase( dst, uppercase ); + } else if ( t === kUppercaseAll ) { + while ( len > 0 ) { + var step = ToUpperCase( dst, uppercase ); + uppercase += step; + len -= step; + } + } + + var suffix_pos = 0; + while ( suffix_pos < suffix.length ) { + dst[ idx++ ] = suffix[ suffix_pos++ ]; + } + + return idx - start_idx; + }; + }, + { './dictionary': 6 }, + ], + 12: [ + function ( require, module, exports ) { + module.exports = + require( './dec/decode' ).BrotliDecompressBuffer; + }, + { './dec/decode': 3 }, + ], + }, + {}, + [ 12 ] + )( 12 ); +} ); +/* eslint-enable */ diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-details.js b/packages/global-styles-ui/src/font-library-modal/library-font-details.tsx similarity index 88% rename from packages/edit-site/src/components/global-styles/font-library-modal/library-font-details.js rename to packages/global-styles-ui/src/font-library-modal/library-font-details.tsx index 57ed50f5bfa240..efe8926de0ae95 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-details.js +++ b/packages/global-styles-ui/src/font-library-modal/library-font-details.tsx @@ -11,8 +11,9 @@ import { */ import LibraryFontVariant from './library-font-variant'; import { sortFontFaces } from './utils/sort-font-faces'; +import type { FontFamily } from './types'; -function LibraryFontDetails( { font } ) { +function LibraryFontDetails( { font }: { font: FontFamily } ) { const fontFaces = font.fontFace && font.fontFace.length ? sortFontFaces( font.fontFace ) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js b/packages/global-styles-ui/src/font-library-modal/library-font-variant.tsx similarity index 80% rename from packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js rename to packages/global-styles-ui/src/font-library-modal/library-font-variant.tsx index 24a1d54871f6bc..872b48b8fb54f8 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js +++ b/packages/global-styles-ui/src/font-library-modal/library-font-variant.tsx @@ -10,23 +10,30 @@ import { CheckboxControl, Flex } from '@wordpress/components'; import { getFontFaceVariantName } from './utils'; import { FontLibraryContext } from './context'; import FontDemo from './font-demo'; +import type { FontFace, FontFamily } from './types'; -function LibraryFontVariant( { face, font } ) { +function LibraryFontVariant( { + face, + font, +}: { + face: FontFace; + font: FontFamily; +} ) { const { isFontActivated, toggleActivateFont } = useContext( FontLibraryContext ); const isInstalled = - font?.fontFace?.length > 0 + ( font?.fontFace?.length ?? 0 ) > 0 ? isFontActivated( font.slug, face.fontStyle, face.fontWeight, font.source ) - : isFontActivated( font.slug, null, null, font.source ); + : isFontActivated( font.slug, undefined, undefined, font.source ); const handleToggleActivation = () => { - if ( font?.fontFace?.length > 0 ) { + if ( ( font?.fontFace?.length ?? 0 ) > 0 ) { toggleActivateFont( font, face ); return; } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js b/packages/global-styles-ui/src/font-library-modal/resolvers.tsx similarity index 52% rename from packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js rename to packages/global-styles-ui/src/font-library-modal/resolvers.tsx index a114630cfc08d1..578beff6e37c0c 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js +++ b/packages/global-styles-ui/src/font-library-modal/resolvers.tsx @@ -1,44 +1,62 @@ /** * WordPress dependencies */ +// The font library modal is pre-existent in Gutenberg +// It needs to be refactored to move all the API calls to core-data. +// eslint-disable-next-line no-restricted-imports import apiFetch from '@wordpress/api-fetch'; +/** + * Internal dependencies + */ +import type { + CollectionFontFace, + CollectionFontFamily, + FontCollection, + FontFace, +} from './types'; + const FONT_FAMILIES_URL = '/wp/v2/font-families'; const FONT_COLLECTIONS_URL = '/wp/v2/font-collections'; -export async function fetchInstallFontFamily( data ) { +export async function fetchInstallFontFamily( data: FormData ) { const config = { path: FONT_FAMILIES_URL, method: 'POST', body: data, }; - const response = await apiFetch( config ); + const response: CollectionFontFamily = await apiFetch( config ); return { - id: response.id, + id: response.id as string, ...response.font_family_settings, fontFace: [], }; } -export async function fetchInstallFontFace( fontFamilyId, data ) { +export async function fetchInstallFontFace( + fontFamilyId: string, + data: FormData +): Promise< FontFace > { const config = { path: `${ FONT_FAMILIES_URL }/${ fontFamilyId }/font-faces`, method: 'POST', body: data, }; - const response = await apiFetch( config ); + const response = ( await apiFetch( config ) ) as CollectionFontFace; return { id: response.id, ...response.font_face_settings, }; } -export async function fetchGetFontFamilyBySlug( slug ) { +export async function fetchGetFontFamilyBySlug( slug: string ) { const config = { path: `${ FONT_FAMILIES_URL }?slug=${ slug }&_embed=true`, method: 'GET', }; - const response = await apiFetch( config ); + const response = ( await apiFetch( config ) ) as + | CollectionFontFamily[] + | undefined; if ( ! response || response.length === 0 ) { return null; } @@ -47,13 +65,17 @@ export async function fetchGetFontFamilyBySlug( slug ) { id: fontFamilyPost.id, ...fontFamilyPost.font_family_settings, fontFace: - fontFamilyPost?._embedded?.font_faces.map( + ( fontFamilyPost?._embedded?.font_faces ?? [] ).map( ( face ) => face.font_face_settings ) || [], }; } -export async function fetchUninstallFontFamily( fontFamilyId ) { +export async function fetchUninstallFontFamily( + fontFamilyId: string +): Promise< { + deleted: boolean; +} > { const config = { path: `${ FONT_FAMILIES_URL }/${ fontFamilyId }?force=true`, method: 'DELETE', @@ -66,13 +88,13 @@ export async function fetchFontCollections() { path: `${ FONT_COLLECTIONS_URL }?_fields=slug,name,description`, method: 'GET', }; - return await apiFetch( config ); + return ( await apiFetch( config ) ) as FontCollection[]; } -export async function fetchFontCollection( id ) { +export async function fetchFontCollection( id: string ) { const config = { path: `${ FONT_COLLECTIONS_URL }/${ id }`, method: 'GET', }; - return await apiFetch( config ); + return ( await apiFetch( config ) ) as FontCollection; } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/style.scss b/packages/global-styles-ui/src/font-library-modal/style.scss similarity index 65% rename from packages/edit-site/src/components/global-styles/font-library-modal/style.scss rename to packages/global-styles-ui/src/font-library-modal/style.scss index f931422436321b..581058b1ff04d4 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/style.scss +++ b/packages/global-styles-ui/src/font-library-modal/style.scss @@ -1,6 +1,6 @@ -@use "@wordpress/base-styles/colors" as *; -@use "@wordpress/base-styles/mixins" as *; -@use "@wordpress/base-styles/variables" as *; +@use "@wordpress/base-styles/mixins"; +@use "@wordpress/base-styles/variables"; +@use "@wordpress/base-styles/colors"; // Fixed height for the modal footer. // Ensures that the footer is always visible when the modal content is scrollable. @@ -11,7 +11,7 @@ $footer-height: 70px; // the content width, we should use that prop instead of this style. // see https://github.com/WordPress/gutenberg/issues/54471. &.font-library-modal { - @include break-medium() { + @include mixins.break-medium() { width: 65vw; } } @@ -27,7 +27,7 @@ $footer-height: 70px; .font-library-modal__subtitle { text-transform: uppercase; - font-weight: $font-weight-medium; + font-weight: variables.$font-weight-medium; font-size: 11px; } @@ -38,7 +38,7 @@ $footer-height: 70px; } .font-library-modal__tabpanel-layout { - margin-top: $grid-unit-40; + margin-top: variables.$grid-unit-40; .font-library-modal__loading { width: 100%; @@ -51,30 +51,36 @@ $footer-height: 70px; justify-content: center; // Push down so that the progress bar is centered vertically. // It should be 120px (72px modal header height + 48px tab height) - padding-top: $header-height + $grid-unit-15 + $grid-unit-60; + padding-top: + variables.$header-height + variables.$grid-unit-15 + + variables.$grid-unit-60; } } .font-library-modal__footer { - border-top: 1px solid $gray-300; - margin: 0 #{$grid-unit-40 * -1} #{$grid-unit-40 * -1}; - padding: $grid-unit-20 $grid-unit-40; + border-top: 1px solid colors.$gray-300; + margin: 0 #{variables.$grid-unit-40 * -1} #{variables.$grid-unit-40 * -1}; + padding: variables.$grid-unit-20 variables.$grid-unit-40; position: absolute; - bottom: $grid-unit-40; + bottom: variables.$grid-unit-40; width: 100%; height: $footer-height; - background-color: $white; + background-color: colors.$white; +} + +.font-library-modal__category-select { + min-width: 40%; } .font-library-modal__page-selection { font-size: 11px; - font-weight: $font-weight-medium; + font-weight: variables.$font-weight-medium; text-transform: uppercase; - @include break-small() { - .components-select-control__input { + @include mixins.break-small() { + .font-library-modal__page-selection-trigger { font-size: 11px !important; - font-weight: $font-weight-medium; + font-weight: variables.$font-weight-medium; } } } @@ -88,6 +94,8 @@ $footer-height: 70px; } .font-library-modal__fonts-list { + list-style: none; + padding: 0; margin-top: 0; margin-bottom: 0; } @@ -97,22 +105,20 @@ $footer-height: 70px; } .font-library-modal__font-card { - border: $border-width solid $gray-200; + border: variables.$border-width solid colors.$gray-300; width: 100%; // Override the default 40px height set by the Button component. // Ref - https://github.com/WordPress/gutenberg/pull/65258#discussion_r1756147260 height: auto !important; - padding: $grid-unit-20; + padding: variables.$grid-unit-20; margin-top: -1px; /* To collapse the margin with the previous element */ - &:hover { - background-color: $gray-100; - } + background-color: colors.$gray-100; - &:focus { - position: relative; + &:hover { + background-color: colors.$gray-100; } .font-library-modal__font-card__name { @@ -120,12 +126,12 @@ $footer-height: 70px; } .font-library-modal__font-card__count { - color: $gray-700; + color: colors.$gray-700; } .font-library-modal__font-variant_demo-image { display: block; - height: $grid-unit-30; + height: variables.$grid-unit-30; width: auto; } @@ -133,24 +139,19 @@ $footer-height: 70px; white-space: nowrap; flex-shrink: 0; - @media not (prefers-reduced-motion) { + @media not ( prefers-reduced-motion ) { transition: opacity 0.3s ease-in-out; } } } -.font-library-modal__font-variant { - border-bottom: 1px solid $gray-200; - padding-bottom: $grid-unit-20; -} - .font-library-modal__tablist-container { position: sticky; top: 0; - border-bottom: 1px solid $gray-300; - background: $white; - margin: 0 #{$grid-unit-40 * -1}; - padding: 0 $grid-unit-20; + border-bottom: 1px solid colors.$gray-300; + background: colors.$white; + margin: 0 #{variables.$grid-unit-40 * -1}; + padding: 0 variables.$grid-unit-20; z-index: 1; [role="tablist"] { @@ -165,13 +166,13 @@ $footer-height: 70px; // Override the default 40px height set by the Button component. // Ref - https://github.com/WordPress/gutenberg/pull/65258#discussion_r1756155039 - height: $grid-unit-80 * 4 !important; // 256px + height: variables.$grid-unit-80 * 4 !important; // 256px width: 100%; } button.font-library-modal__upload-area { - background-color: $gray-100; + background-color: colors.$gray-100; } .font-library-modal__local-fonts { @@ -179,7 +180,7 @@ button.font-library-modal__upload-area { width: 80%; .font-library-modal__upload-area__text { - color: $gray-700; + color: colors.$gray-700; } } @@ -187,10 +188,10 @@ button.font-library-modal__upload-area { display: flex; justify-content: center; align-items: center; - margin-top: $grid-unit-80; + margin-top: variables.$grid-unit-80; p { - line-height: $default-line-height; + line-height: variables.$default-line-height; } h2 { @@ -199,7 +200,7 @@ button.font-library-modal__upload-area { } .components-card { - padding: $grid-unit-20; + padding: variables.$grid-unit-20; width: 400px; } @@ -211,10 +212,11 @@ button.font-library-modal__upload-area { .font-library-modal__select-all { padding: - $grid-unit-20 $grid-unit-20 $grid-unit-20 $grid-unit-20 + - $border-width; + variables.$grid-unit-20 variables.$grid-unit-20 + variables.$grid-unit-20 variables.$grid-unit-20 + + variables.$border-width; .components-checkbox-control__label { - padding-left: $grid-unit-20; + padding-left: variables.$grid-unit-20; } } diff --git a/packages/global-styles-ui/src/font-library-modal/types.ts b/packages/global-styles-ui/src/font-library-modal/types.ts new file mode 100644 index 00000000000000..5824a29b9dfd74 --- /dev/null +++ b/packages/global-styles-ui/src/font-library-modal/types.ts @@ -0,0 +1,176 @@ +/** + * WordPress dependencies + */ +import type { FontFamilyPreset } from '@wordpress/global-styles-engine'; + +export interface CollectionFontFace { + id: string; + font_face_settings: FontFace; +} + +export interface FontFace { + fontFamily: string; + fontStyle?: string; + fontWeight?: string | number; + src?: string | string[]; + preview?: string; + file?: File | File[]; + fake?: boolean; + id?: string; + fontDisplay?: string; + fontStretch?: string; + fontVariant?: string; + fontFeatureSettings?: string; + fontVariationSettings?: string; + unicodeRange?: string; +} + +export interface CollectionFontFamily { + id: string; + font_family_settings: FontFamily; + categories?: string[]; + _embedded?: { + font_faces?: CollectionFontFace[]; + }; +} + +export interface FontFamily { + name: string; + slug: string; + fontFamily: string; + fontFace?: FontFace[]; + preview?: string; + id?: string; + source?: string; + version?: string; + author?: string; + license?: string; + description?: string; + tags?: string[]; + variants?: FontFace[]; + category?: string; +} + +export interface FontCollection { + id: string; + slug: string; + name: string; + description?: string; + font_families?: CollectionFontFamily[]; + categories?: { + slug: string; + name: string; + }[]; +} + +export interface FontLibraryState { + isInstalling: boolean; + fontFamilies: Record< string, FontFamilyPreset[] >; + notice?: { + type: 'success' | 'error' | 'info'; + message: string; + }; + loadFontFaceAsset: ( fontFace: FontFace ) => Promise< void >; + installFonts: ( fonts: FontFamily[] ) => Promise< void >; + uninstallFontFamily: ( fontFamily: FontFamily ) => Promise< { + deleted: boolean; + } >; + refreshLibrary: () => void; + // Additional properties found in the codebase + baseCustomFonts: FontFamily[]; + modalTabOpen: string; + setModalTabOpen: ( tab: string ) => void; + handleSetLibraryFontSelected: ( font?: FontFamily ) => void; + libraryFontSelected?: FontFamily; + isFontActivated: ( + slug: string, + style?: string, + weight?: string | number, + source?: string + ) => boolean; + getFontFacesActivated: ( slug: string, source?: string ) => string[]; + toggleActivateFont: ( font: FontFamily, face?: FontFace ) => void; + getAvailableFontsOutline: ( + availableFontFamilies: FontFamily[] + ) => Record< string, string[] >; + saveFontFamilies: ( + fonts: + | FontFamilyPreset[] + | Record< string, FontFamilyPreset[] > + | undefined + ) => Promise< void >; + isResolvingLibrary: boolean; + collections: FontCollection[]; + getFontCollection: ( slug: string ) => Promise< FontCollection | void >; +} + +export interface FontDemoProps { + font: FontFamily | FontFace; + text?: string; + onClick?: () => void; +} + +export interface FontCardProps { + font: FontFamily; + onClick?: () => void; + variantsText?: string; +} + +export interface FontVariantProps { + fontFace: FontFace; + fontFamily: FontFamily; + isSelected?: boolean; + onClick?: () => void; +} + +export interface CollectionFontVariantProps { + face: FontFace; + font: FontFamily; + handleToggleVariant: ( font: FontFamily, face?: FontFace ) => void; + selected: boolean; +} + +export interface FontUploadResult { + successes: FontFace[]; + errors: Array< { + data: FormData; + message: string; + } >; +} + +export interface GoogleFontsAPIResponse { + items: Array< { + family: string; + variants: string[]; + subsets: string[]; + version: string; + lastModified: string; + files: Record< string, string >; + category: string; + kind: string; + menu: string; + } >; +} + +export type FontWeight = + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900'; +export type FontStyle = 'normal' | 'italic'; +export type FontDisplay = 'auto' | 'block' | 'swap' | 'fallback' | 'optional'; +export type FontStretch = + | 'normal' + | 'ultra-condensed' + | 'extra-condensed' + | 'condensed' + | 'semi-condensed' + | 'semi-expanded' + | 'expanded' + | 'extra-expanded' + | 'ultra-expanded'; diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/upload-fonts.js b/packages/global-styles-ui/src/font-library-modal/upload-fonts.tsx similarity index 80% rename from packages/edit-site/src/components/global-styles/font-library-modal/upload-fonts.js rename to packages/global-styles-ui/src/font-library-modal/upload-fonts.tsx index 807f2aa354c25a..828a40c05decf6 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/upload-fonts.js +++ b/packages/global-styles-ui/src/font-library-modal/upload-fonts.tsx @@ -20,19 +20,24 @@ import { useContext, useState } from '@wordpress/element'; */ import { ALLOWED_FILE_EXTENSIONS } from './utils/constants'; import { FontLibraryContext } from './context'; -import { Font } from '../../../../lib/lib-font.browser'; +import { Font } from './lib/lib-font.browser'; import makeFamiliesFromFaces from './utils/make-families-from-faces'; import { loadFontFaceInBrowser } from './utils'; +import type { FontFace } from './types'; function UploadFonts() { const { installFonts } = useContext( FontLibraryContext ); const [ isUploading, setIsUploading ] = useState( false ); - const [ notice, setNotice ] = useState( false ); + const [ notice, setNotice ] = useState< { + type: 'success' | 'error'; + message: string; + errors?: string[]; + } | null >( null ); - const handleDropZone = ( files ) => { + const handleDropZone = ( files: File[] ) => { handleFilesUpload( files ); }; - const onFilesUpload = ( event ) => { + const onFilesUpload = ( event: React.ChangeEvent< HTMLInputElement > ) => { handleFilesUpload( event.target.files ); }; @@ -42,7 +47,10 @@ function UploadFonts() { * @param {Array} files The files to be filtered * @return {void} */ - const handleFilesUpload = async ( files ) => { + const handleFilesUpload = async ( files: FileList | File[] | null ) => { + if ( ! files ) { + return; + } setNotice( null ); setIsUploading( true ); const uniqueFilenames = new Set(); @@ -61,7 +69,9 @@ function UploadFonts() { return null; // Return null for duplicates. } // Check if the file extension is allowed. - const fileExtension = file.name.split( '.' ).pop().toLowerCase(); + const fileExtension = ( + ( ( file.name ?? '' ).split( '.' ) ?? [] ).pop() ?? '' + ).toLowerCase(); if ( ALLOWED_FILE_EXTENSIONS.includes( fileExtension ) ) { uniqueFilenames.add( file.name ); return file; // Return the file if it passes all checks. @@ -70,9 +80,9 @@ function UploadFonts() { } ); // Filter out the nulls after all promises have resolved. - const allowedFiles = ( await Promise.all( checkFilesPromises ) ).filter( - ( file ) => null !== file - ); + const allowedFiles: File[] = ( + await Promise.all( checkFilesPromises ) + ).filter( ( file ) => null !== file ); if ( allowedFiles.length > 0 ) { loadFiles( allowedFiles ); @@ -95,9 +105,9 @@ function UploadFonts() { * @param {Array} files The files to be loaded * @return {void} */ - const loadFiles = async ( files ) => { + const loadFiles = async ( files: File[] ) => { const fontFacesLoaded = await Promise.all( - files.map( async ( fontFile ) => { + files.map( async ( fontFile: File ) => { const fontFaceData = await getFontFaceMetadata( fontFile ); await loadFontFaceInBrowser( fontFaceData, @@ -116,19 +126,20 @@ function UploadFonts() { * @param {File} file The file to be checked. * @return {boolean} Whether the file is a valid font file. */ - async function isFontFile( file ) { + async function isFontFile( file: File ) { const font = new Font( 'Uploaded Font' ); try { const buffer = await readFileAsArrayBuffer( file ); await font.fromDataBuffer( buffer, 'font' ); return true; + // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch ( error ) { return false; } } // Create a function to read the file as array buffer - async function readFileAsArrayBuffer( file ) { + async function readFileAsArrayBuffer( file: File ) { return new Promise( ( resolve, reject ) => { const reader = new window.FileReader(); reader.readAsArrayBuffer( file ); @@ -137,12 +148,14 @@ function UploadFonts() { } ); } - const getFontFaceMetadata = async ( fontFile ) => { + const getFontFaceMetadata = async ( fontFile: File ) => { const buffer = await readFileAsArrayBuffer( fontFile ); - const fontObj = new Font( 'Uploaded Font' ); + const fontObj: Font & { + onload?: ( val: { detail: { font: any } } ) => void; + } = new Font( 'Uploaded Font' ); fontObj.fromDataBuffer( buffer, fontFile.name ); // Assuming that fromDataBuffer triggers onload event and returning a Promise - const onloadEvent = await new Promise( + const onloadEvent: { detail: { font: any } } = await new Promise( ( resolve ) => ( fontObj.onload = resolve ) ); const font = onloadEvent.detail.font; @@ -155,7 +168,7 @@ function UploadFonts() { const weightAxis = isVariable && font.opentype.tables.fvar.axes.find( - ( { tag } ) => tag === 'wght' + ( { tag }: { tag: string } ) => tag === 'wght' ); const weightRange = weightAxis ? `${ weightAxis.minValue } ${ weightAxis.maxValue }` @@ -174,7 +187,7 @@ function UploadFonts() { * @param {Array} fontFaces The font faces to be installed * @return {void} */ - const handleInstall = async ( fontFaces ) => { + const handleInstall = async ( fontFaces: FontFace[] ) => { const fontFamilies = makeFamiliesFromFaces( fontFaces ); try { @@ -184,10 +197,13 @@ function UploadFonts() { message: __( 'Fonts were installed successfully.' ), } ); } catch ( error ) { + const typedError = error as Error & { + installationErrors?: string[]; + }; setNotice( { type: 'error', - message: error.message, - errors: error?.installationErrors, + message: typedError.message, + errors: typedError?.installationErrors, } ); } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/constants.js b/packages/global-styles-ui/src/font-library-modal/utils/constants.ts similarity index 83% rename from packages/edit-site/src/components/global-styles/font-library-modal/utils/constants.js rename to packages/global-styles-ui/src/font-library-modal/utils/constants.ts index 4b2b9d1f5fc11e..519b8ffa430535 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/constants.js +++ b/packages/global-styles-ui/src/font-library-modal/utils/constants.ts @@ -5,7 +5,7 @@ import { _x } from '@wordpress/i18n'; export const ALLOWED_FILE_EXTENSIONS = [ 'otf', 'ttf', 'woff', 'woff2' ]; -export const FONT_WEIGHTS = { +export const FONT_WEIGHTS: Record< string, string > = { 100: _x( 'Thin', 'font weight' ), 200: _x( 'Extra-light', 'font weight' ), 300: _x( 'Light', 'font weight' ), @@ -17,7 +17,7 @@ export const FONT_WEIGHTS = { 900: _x( 'Black', 'font weight' ), }; -export const FONT_STYLES = { +export const FONT_STYLES: Record< string, string > = { normal: _x( 'Normal', 'font style' ), italic: _x( 'Italic', 'font style' ), }; diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/filter-fonts.js b/packages/global-styles-ui/src/font-library-modal/utils/filter-fonts.ts similarity index 51% rename from packages/edit-site/src/components/global-styles/font-library-modal/utils/filter-fonts.js rename to packages/global-styles-ui/src/font-library-modal/utils/filter-fonts.ts index e493a70197acee..5cb637e05bd09c 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/filter-fonts.js +++ b/packages/global-styles-ui/src/font-library-modal/utils/filter-fonts.ts @@ -1,3 +1,8 @@ +/** + * Internal dependencies + */ +import type { CollectionFontFamily } from '../types'; + /** * Filters a list of fonts based on the specified filters. * @@ -7,27 +12,34 @@ * Additionally, if a search term is provided, it filters the fonts array to include only those fonts * whose name includes the search term, case-insensitively. * - * @param {Array} fonts Array of font objects in font-collection schema fashion to be filtered. Each font object should have a 'categories' property and a 'font_family_settings' property with a 'name' key. - * @param {Object} filters Object containing the filter criteria. It should have a 'category' key and/or a 'search' key. - * The 'category' key is a string representing the category to filter by. - * The 'search' key is a string representing the search term to filter by. - * @return {Array} Array of filtered font objects based on the provided criteria. + * @param fonts Array of font objects in font-collection schema fashion to be filtered. Each font object should have a 'categories' property and a 'font_family_settings' property with a 'name' key. + * @param filters Object containing the filter criteria. It should have a 'category' key and/or a 'search' key. + * @param filters.category The category to filter fonts by. If 'all', no category filtering is applied. + * @param filters.search The search term to filter fonts by. If provided, only fonts whose + * + * @return Array of filtered font objects based on the provided criteria. */ -export default function filterFonts( fonts, filters ) { +export default function filterFonts( + fonts: CollectionFontFamily[], + filters: { category?: string; search?: string } +): CollectionFontFamily[] { const { category, search } = filters; let filteredFonts = fonts || []; if ( category && category !== 'all' ) { filteredFonts = filteredFonts.filter( - ( font ) => font.categories.indexOf( category ) !== -1 + ( font ) => + font.categories && font.categories.indexOf( category ) !== -1 ); } if ( search ) { - filteredFonts = filteredFonts.filter( ( font ) => - font.font_family_settings.name - .toLowerCase() - .includes( search.toLowerCase() ) + filteredFonts = filteredFonts.filter( + ( font ) => + font.font_family_settings && + font.font_family_settings.name + .toLowerCase() + .includes( search.toLowerCase() ) ); } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/fonts-outline.js b/packages/global-styles-ui/src/font-library-modal/utils/fonts-outline.ts similarity index 52% rename from packages/edit-site/src/components/global-styles/font-library-modal/utils/fonts-outline.js rename to packages/global-styles-ui/src/font-library-modal/utils/fonts-outline.ts index bef9353e943505..102c8b1fb94a4d 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/fonts-outline.js +++ b/packages/global-styles-ui/src/font-library-modal/utils/fonts-outline.ts @@ -1,4 +1,11 @@ -export function getFontsOutline( fonts ) { +/** + * Internal dependencies + */ +import type { FontFace, FontFamily } from '../types'; + +export function getFontsOutline( + fonts: FontFamily[] +): Record< string, Record< string, boolean > > { return fonts.reduce( ( acc, font ) => ( { ...acc, @@ -14,7 +21,11 @@ export function getFontsOutline( fonts ) { ); } -export function isFontFontFaceInOutline( slug, face, outline ) { +export function isFontFontFaceInOutline( + slug: string, + face: FontFace | null, + outline: Record< string, Record< string, boolean > > +): boolean { if ( ! face ) { return !! outline[ slug ]; } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/global-styles-ui/src/font-library-modal/utils/index.ts similarity index 73% rename from packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js rename to packages/global-styles-ui/src/font-library-modal/utils/index.ts index 1ca7bb68c87a06..3f14905e6bbd29 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/global-styles-ui/src/font-library-modal/utils/index.ts @@ -7,9 +7,10 @@ import { privateApis as componentsPrivateApis } from '@wordpress/components'; * Internal dependencies */ import { FONT_WEIGHTS, FONT_STYLES } from './constants'; -import { unlock } from '../../../../lock-unlock'; import { fetchInstallFontFace } from '../resolvers'; import { formatFontFaceName } from './preview-styles'; +import type { FontFamily, FontFace, FontUploadResult } from '../types'; +import { unlock } from '../../lock-unlock'; /** * Browser dependencies @@ -17,7 +18,10 @@ import { formatFontFaceName } from './preview-styles'; const { File } = window; const { kebabCase } = unlock( componentsPrivateApis ); -export function setUIValuesNeeded( font, extraValues = {} ) { +export function setUIValuesNeeded( + font: FontFamily, + extraValues: Partial< FontFamily > = {} +): FontFamily { if ( ! font.name && ( font.fontFamily || font.slug ) ) { font.name = font.fontFamily || font.slug; } @@ -27,23 +31,26 @@ export function setUIValuesNeeded( font, extraValues = {} ) { }; } -export function isUrlEncoded( url ) { +export function isUrlEncoded( url: string ): boolean { if ( typeof url !== 'string' ) { return false; } return url !== decodeURIComponent( url ); } -export function getFontFaceVariantName( face ) { - const weightName = FONT_WEIGHTS[ face.fontWeight ] || face.fontWeight; +export function getFontFaceVariantName( face: FontFace ): string { + const weightName = FONT_WEIGHTS[ face.fontWeight ?? '' ] || face.fontWeight; const styleName = face.fontStyle === 'normal' ? '' - : FONT_STYLES[ face.fontStyle ] || face.fontStyle; + : FONT_STYLES[ face.fontStyle ?? '' ] || face.fontStyle; return `${ weightName } ${ styleName }`; } -export function mergeFontFaces( existing = [], incoming = [] ) { +export function mergeFontFaces( + existing: FontFace[] = [], + incoming: FontFace[] = [] +): FontFace[] { const map = new Map(); for ( const face of existing ) { map.set( `${ face.fontWeight }${ face.fontStyle }`, face ); @@ -55,7 +62,10 @@ export function mergeFontFaces( existing = [], incoming = [] ) { return Array.from( map.values() ); } -export function mergeFontFamilies( existing = [], incoming = [] ) { +export function mergeFontFamilies( + existing: FontFamily[] = [], + incoming: FontFamily[] = [] +): FontFamily[] { const map = new Map(); // Add the existing array to the map. for ( const font of existing ) { @@ -87,7 +97,11 @@ export function mergeFontFamilies( existing = [], incoming = [] ) { * Loads the font face from a URL and adds it to the browser. * It also adds it to the iframe document. */ -export async function loadFontFaceInBrowser( fontFace, source, addTo = 'all' ) { +export async function loadFontFaceInBrowser( + fontFace: FontFace, + source: string | File, + addTo: 'all' | 'document' | 'iframe' = 'all' +): Promise< void > { let dataSource; if ( typeof source === 'string' ) { @@ -104,7 +118,7 @@ export async function loadFontFaceInBrowser( fontFace, source, addTo = 'all' ) { dataSource, { style: fontFace.fontStyle, - weight: fontFace.fontWeight, + weight: String( fontFace.fontWeight ), } ); @@ -115,10 +129,12 @@ export async function loadFontFaceInBrowser( fontFace, source, addTo = 'all' ) { } if ( addTo === 'iframe' || addTo === 'all' ) { - const iframeDocument = document.querySelector( + const iframe = document.querySelector( 'iframe[name="editor-canvas"]' - ).contentDocument; - iframeDocument.fonts.add( loadedFace ); + ) as HTMLIFrameElement; + if ( iframe?.contentDocument ) { + iframe.contentDocument.fonts.add( loadedFace ); + } } } @@ -131,8 +147,11 @@ export async function loadFontFaceInBrowser( fontFace, source, addTo = 'all' ) { * * @see https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/delete. */ -export function unloadFontFaceInBrowser( fontFace, removeFrom = 'all' ) { - const unloadFontFace = ( fonts ) => { +export function unloadFontFaceInBrowser( + fontFace: FontFace, + removeFrom: 'all' | 'document' | 'iframe' = 'all' +): void { + const unloadFontFace = ( fonts: FontFaceSet ) => { fonts.forEach( ( f ) => { if ( f.family === formatFontFaceName( fontFace?.fontFamily ) && @@ -149,10 +168,12 @@ export function unloadFontFaceInBrowser( fontFace, removeFrom = 'all' ) { } if ( removeFrom === 'iframe' || removeFrom === 'all' ) { - const iframeDocument = document.querySelector( + const iframe = document.querySelector( 'iframe[name="editor-canvas"]' - ).contentDocument; - unloadFontFace( iframeDocument.fonts ); + ) as HTMLIFrameElement; + if ( iframe?.contentDocument ) { + unloadFontFace( iframe.contentDocument.fonts ); + } } } @@ -162,7 +183,9 @@ export function unloadFontFaceInBrowser( fontFace, removeFrom = 'all' ) { * @param {string|string[]} input - The font face src. * @return {string|undefined} The display source or undefined if the input is invalid. */ -export function getDisplaySrcFromFontFace( input ) { +export function getDisplaySrcFromFontFace( + input: string | string[] +): string | undefined { if ( ! input ) { return; } @@ -183,9 +206,10 @@ export function getDisplaySrcFromFontFace( input ) { return src; } -export function makeFontFamilyFormData( fontFamily ) { +export function makeFontFamilyFormData( fontFamily: FontFamily ): FormData { const formData = new FormData(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { fontFace, category, ...familyWithValidParameters } = fontFamily; const fontFamilySettings = { ...familyWithValidParameters, @@ -199,9 +223,9 @@ export function makeFontFamilyFormData( fontFamily ) { return formData; } -export function makeFontFacesFormData( font ) { - if ( font?.fontFace ) { - const fontFacesFormData = font.fontFace.map( ( item, faceIndex ) => { +export function makeFontFacesFormData( font: FontFamily ): FormData[] { + const fontFacesFormData = ( font?.fontFace ?? [] ).map( + ( item, faceIndex ) => { const face = { ...item }; const formData = new FormData(); if ( face.file ) { @@ -209,7 +233,7 @@ export function makeFontFacesFormData( font ) { const files = Array.isArray( face.file ) ? face.file : [ face.file ]; - const src = []; + const src: string[] = []; files.forEach( ( file, key ) => { // Slugified file name because the it might contain spaces or characters treated differently on the server. @@ -227,14 +251,21 @@ export function makeFontFacesFormData( font ) { formData.append( 'font_face_settings', JSON.stringify( face ) ); } return formData; - } ); + } + ); - return fontFacesFormData; - } + return fontFacesFormData; } -export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { - const responses = []; +export async function batchInstallFontFaces( + fontFamilyId: string, + fontFacesData: FormData[] +): Promise< FontUploadResult > { + const responses: { + status: 'fulfilled' | 'rejected'; + value?: FontFace; + reason?: Error; + }[] = []; /* * Uses the same response format as Promise.allSettled, but executes requests in sequence to work @@ -248,27 +279,26 @@ export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { ); responses.push( { status: 'fulfilled', value: response } ); } catch ( error ) { - responses.push( { status: 'rejected', reason: error } ); + responses.push( { status: 'rejected', reason: error as Error } ); } } - const results = { + const results: { + successes: FontFace[]; + errors: Array< { + data: FormData; + message: string; + } >; + } = { errors: [], successes: [], }; responses.forEach( ( result, index ) => { - if ( result.status === 'fulfilled' ) { + if ( result.status === 'fulfilled' && result.value ) { const response = result.value; - if ( response.id ) { - results.successes.push( response ); - } else { - results.errors.push( { - data: fontFacesData[ index ], - message: `Error: ${ response.message }`, - } ); - } - } else { + results.successes.push( response ); + } else if ( result.reason ) { // Handle network errors or other fetch-related errors results.errors.push( { data: fontFacesData[ index ], @@ -283,7 +313,9 @@ export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { /* * Downloads a font face asset from a URL to the client and returns a File object. */ -export async function downloadFontFaceAssets( src ) { +export async function downloadFontFaceAssets( + src: string | string[] +): Promise< File | File[] > { // Normalize to an array, since `src` could be a string or array. src = Array.isArray( src ) ? src : [ src ]; @@ -299,7 +331,7 @@ export async function downloadFontFaceAssets( src ) { return response.blob(); } ) .then( ( blob ) => { - const filename = url.split( '/' ).pop(); + const filename = url.split( '/' ).pop() as string; const file = new File( [ blob ], filename, { type: blob.type, } ); @@ -320,7 +352,10 @@ export async function downloadFontFaceAssets( src ) { * @param {Array} collection The Collection to seek in * @returns True if the font face is found in the collection. Otherwise False. */ -export function checkFontFaceInstalled( fontFace, collection ) { +export function checkFontFaceInstalled( + fontFace: FontFace, + collection: FontFace[] +): boolean { return ( -1 !== collection.findIndex( ( collectionFontFace ) => { diff --git a/packages/global-styles-ui/src/font-library-modal/utils/make-families-from-faces.ts b/packages/global-styles-ui/src/font-library-modal/utils/make-families-from-faces.ts new file mode 100644 index 00000000000000..0150a035b4eab6 --- /dev/null +++ b/packages/global-styles-ui/src/font-library-modal/utils/make-families-from-faces.ts @@ -0,0 +1,34 @@ +/** + * WordPress dependencies + */ +import { privateApis as componentsPrivateApis } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import type { FontFamily, FontFace } from '../types'; +import { unlock } from '../../lock-unlock'; + +const { kebabCase } = unlock( componentsPrivateApis ); + +export default function makeFamiliesFromFaces( + fontFaces: FontFace[] +): FontFamily[] { + const fontFamiliesObject = fontFaces.reduce( + ( acc: Record< string, FontFamily >, item: FontFace ) => { + if ( ! acc[ item.fontFamily ] ) { + acc[ item.fontFamily ] = { + name: item.fontFamily, + fontFamily: item.fontFamily, + slug: kebabCase( item.fontFamily.toLowerCase() ), + fontFace: [], + }; + } + // @ts-expect-error + acc[ item.fontFamily ].fontFace.push( item ); + return acc; + }, + {} + ); + return Object.values( fontFamiliesObject ) as FontFamily[]; +} diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/preview-styles.js b/packages/global-styles-ui/src/font-library-modal/utils/preview-styles.ts similarity index 81% rename from packages/edit-site/src/components/global-styles/font-library-modal/utils/preview-styles.js rename to packages/global-styles-ui/src/font-library-modal/utils/preview-styles.ts index d0b5d1389d8019..7c664bfad35528 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/preview-styles.js +++ b/packages/global-styles-ui/src/font-library-modal/utils/preview-styles.ts @@ -1,4 +1,14 @@ -function findNearest( input, numbers ) { +/** + * External dependencies + */ +import type { CSSProperties } from 'react'; + +/** + * Internal dependencies + */ +import type { FontFace, FontFamily } from '../types'; + +function findNearest( input: number, numbers: number[] ) { // If the numbers array is empty, return null if ( numbers.length === 0 ) { return null; @@ -9,8 +19,8 @@ function findNearest( input, numbers ) { return numbers[ 0 ]; } -function extractFontWeights( fontFaces ) { - const result = []; +function extractFontWeights( fontFaces: FontFace[] ): number[] { + const result: number[] = []; fontFaces.forEach( ( face ) => { const weights = String( face.fontWeight ).split( ' ' ); @@ -46,12 +56,12 @@ function extractFontWeights( fontFaces ) { * formatFontFamily( "DotGothic16, Slabo 27px, serif" ) => '"DotGothic16","Slabo 27px",serif' * formatFontFamily( "Mine's, Moe's Typography" ) => `"mine's","Moe's Typography"` */ -export function formatFontFamily( input ) { +export function formatFontFamily( input: string ) { // Matches strings that are not exclusively alphabetic characters or hyphens, and do not exactly follow the pattern generic(alphabetic characters or hyphens). const regex = /^(?!generic\([ a-zA-Z\-]+\)$)(?!^[a-zA-Z\-]+$).+/; const output = input.trim(); - const formatItem = ( item ) => { + const formatItem = ( item: string ) => { item = item.trim(); if ( item.match( regex ) ) { // removes leading and trailing quotes. @@ -86,18 +96,19 @@ export function formatFontFamily( input ) { * formatFontFaceName("'Open Sans', sans-serif") => "Open Sans" * formatFontFaceName(", 'Open Sans', 'Helvetica Neue', sans-serif") => "Open Sans" */ -export function formatFontFaceName( input ) { +export function formatFontFaceName( input: string ) { if ( ! input ) { return ''; } let output = input.trim(); if ( output.includes( ',' ) ) { - output = output - .split( ',' ) - // finds the first item that is not an empty string. - .find( ( item ) => item.trim() !== '' ) - .trim(); + output = ( + output + .split( ',' ) + // finds the first item that is not an empty string. + .find( ( item ) => item.trim() !== '' ) ?? '' + ).trim(); } // removes leading and trailing quotes. output = output.replace( /^["']|["']$/g, '' ); @@ -109,10 +120,14 @@ export function formatFontFaceName( input ) { return output; } -export function getFamilyPreviewStyle( family ) { - const style = { fontFamily: formatFontFamily( family.fontFamily ) }; +export function getFamilyPreviewStyle( + family: FontFamily | FontFace +): CSSProperties { + const style: CSSProperties = { + fontFamily: formatFontFamily( family.fontFamily ), + }; - if ( ! Array.isArray( family.fontFace ) ) { + if ( ! ( 'fontFace' in family ) || ! Array.isArray( family.fontFace ) ) { style.fontWeight = '400'; style.fontStyle = 'normal'; return style; @@ -143,7 +158,7 @@ export function getFamilyPreviewStyle( family ) { return style; } -export function getFacePreviewStyle( face ) { +export function getFacePreviewStyle( face: FontFace ): CSSProperties { return { fontFamily: formatFontFamily( face.fontFamily ), fontStyle: face.fontStyle || 'normal', diff --git a/packages/global-styles-ui/src/font-library-modal/utils/set-immutably.ts b/packages/global-styles-ui/src/font-library-modal/utils/set-immutably.ts new file mode 100644 index 00000000000000..9d449764b05481 --- /dev/null +++ b/packages/global-styles-ui/src/font-library-modal/utils/set-immutably.ts @@ -0,0 +1,37 @@ +/** + * Immutably sets a value inside an object. Like `lodash#set`, but returning a + * new object. Treats nullish initial values as empty objects. Clones any + * nested objects. Supports arrays, too. + * Duplicated from `packages/global-styles-engine/src/utils/object.ts` + * + * @param object Object to set a value in. + * @param path Path in the object to modify. + * @param value New value to set. + * @return Cloned object with the new value set. + */ +export function setImmutably( + object: Object, + path: string | number | ( string | number )[], + value: any +) { + // Normalize path + path = Array.isArray( path ) ? [ ...path ] : [ path ]; + + // Shallowly clone the base of the object + object = Array.isArray( object ) ? [ ...object ] : { ...object }; + + const leaf = path.pop(); + + // Traverse object from root to leaf, shallowly cloning at each level + let prev = object; + for ( const key of path ) { + // @ts-expect-error + const lvl = prev[ key ]; + // @ts-expect-error + prev = prev[ key ] = Array.isArray( lvl ) ? [ ...lvl ] : { ...lvl }; + } + // @ts-expect-error + prev[ leaf ] = value; + + return object; +} diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/sort-font-faces.js b/packages/global-styles-ui/src/font-library-modal/utils/sort-font-faces.ts similarity index 61% rename from packages/edit-site/src/components/global-styles/font-library-modal/utils/sort-font-faces.js rename to packages/global-styles-ui/src/font-library-modal/utils/sort-font-faces.ts index 69798112f07d3f..ce3eba13e32d83 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/sort-font-faces.js +++ b/packages/global-styles-ui/src/font-library-modal/utils/sort-font-faces.ts @@ -1,4 +1,9 @@ -function getNumericFontWeight( value ) { +/** + * Internal dependencies + */ +import type { FontFace } from '../types'; + +function getNumericFontWeight( value: string ): number { switch ( value ) { case 'normal': return 400; @@ -13,7 +18,7 @@ function getNumericFontWeight( value ) { } } -export function sortFontFaces( faces ) { +export function sortFontFaces( faces: FontFace[] ): FontFace[] { return faces.sort( ( a, b ) => { // Ensure 'normal' fontStyle is always first if ( a.fontStyle === 'normal' && b.fontStyle !== 'normal' ) { @@ -26,12 +31,16 @@ export function sortFontFaces( faces ) { // If both fontStyles are the same, sort by fontWeight if ( a.fontStyle === b.fontStyle ) { return ( - getNumericFontWeight( a.fontWeight ) - - getNumericFontWeight( b.fontWeight ) + getNumericFontWeight( a.fontWeight?.toString() ?? 'normal' ) - + getNumericFontWeight( b.fontWeight?.toString() ?? 'normal' ) ); } // Sort other fontStyles alphabetically + if ( ! a.fontStyle || ! b.fontStyle ) { + return ! a.fontStyle ? 1 : -1; + } + return a.fontStyle.localeCompare( b.fontStyle ); } ); } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/toggleFont.js b/packages/global-styles-ui/src/font-library-modal/utils/toggleFont.ts similarity index 71% rename from packages/edit-site/src/components/global-styles/font-library-modal/utils/toggleFont.js rename to packages/global-styles-ui/src/font-library-modal/utils/toggleFont.ts index 26cd0af9fea8ea..4f11051ed346e1 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/toggleFont.js +++ b/packages/global-styles-ui/src/font-library-modal/utils/toggleFont.ts @@ -30,31 +30,48 @@ * toggleFont({ slug: 'roboto' }, { fontWeight: '500', fontStyle: 'normal' }, customFonts); * // This will add the specified face to 'roboto' in customFonts */ -export function toggleFont( font, face, initialfonts ) { +/** + * Internal dependencies + */ +import type { FontFamily, FontFace } from '../types'; + +export function toggleFont( + font: FontFamily, + face?: FontFace, + initialfonts: FontFamily[] = [] +): FontFamily[] { // Helper to check if a font is activated based on its slug - const isFontActivated = ( f ) => f.slug === font.slug; + const isFontActivated = ( f: FontFamily ): boolean => f.slug === font.slug; // Helper to get the activated font from a list of fonts - const getActivatedFont = ( fonts ) => fonts.find( isFontActivated ); + const getActivatedFont = ( fonts: FontFamily[] ): FontFamily | undefined => + fonts.find( isFontActivated ); // Toggle the activation status of an entire font family - const toggleEntireFontFamily = ( activatedFont ) => { + const toggleEntireFontFamily = ( + activatedFont: FontFamily | undefined + ): FontFamily[] => { if ( ! activatedFont ) { // If the font is not active, activate the entire font family return [ ...initialfonts, font ]; } // If the font is already active, deactivate the entire font family - return initialfonts.filter( ( f ) => ! isFontActivated( f ) ); + return initialfonts.filter( + ( f: FontFamily ) => ! isFontActivated( f ) + ); }; // Toggle the activation status of a specific font variant - const toggleFontVariant = ( activatedFont ) => { - const isFaceActivated = ( f ) => - f.fontWeight === face.fontWeight && f.fontStyle === face.fontStyle; + const toggleFontVariant = ( + activatedFont: FontFamily | undefined + ): FontFamily[] => { + const isFaceActivated = ( f: FontFace ): boolean => + f.fontWeight === face!.fontWeight && + f.fontStyle === face!.fontStyle; if ( ! activatedFont ) { // If the font family is not active, activate the font family with the font variant - return [ ...initialfonts, { ...font, fontFace: [ face ] } ]; + return [ ...initialfonts, { ...font, fontFace: [ face! ] } ]; } let newFontFaces = activatedFont.fontFace || []; @@ -62,20 +79,22 @@ export function toggleFont( font, face, initialfonts ) { if ( newFontFaces.find( isFaceActivated ) ) { // If the font variant is active, deactivate it newFontFaces = newFontFaces.filter( - ( f ) => ! isFaceActivated( f ) + ( f: FontFace ) => ! isFaceActivated( f ) ); } else { // If the font variant is not active, activate it - newFontFaces = [ ...newFontFaces, face ]; + newFontFaces = [ ...newFontFaces, face! ]; } // If there are no more font faces, deactivate the font family if ( newFontFaces.length === 0 ) { - return initialfonts.filter( ( f ) => ! isFontActivated( f ) ); + return initialfonts.filter( + ( f: FontFamily ) => ! isFontActivated( f ) + ); } // Return updated fonts list with toggled font variant - return initialfonts.map( ( f ) => + return initialfonts.map( ( f: FontFamily ) => isFontActivated( f ) ? { ...f, fontFace: newFontFaces } : f ); }; diff --git a/packages/edit-site/src/components/global-styles/font-sizes/confirm-delete-font-size-dialog.js b/packages/global-styles-ui/src/font-sizes/confirm-delete-font-size-dialog.tsx similarity index 76% rename from packages/edit-site/src/components/global-styles/font-sizes/confirm-delete-font-size-dialog.js rename to packages/global-styles-ui/src/font-sizes/confirm-delete-font-size-dialog.tsx index 69d561ee0232a8..c02232c974e06f 100644 --- a/packages/edit-site/src/components/global-styles/font-sizes/confirm-delete-font-size-dialog.js +++ b/packages/global-styles-ui/src/font-sizes/confirm-delete-font-size-dialog.tsx @@ -3,13 +3,21 @@ */ import { __experimentalConfirmDialog as ConfirmDialog } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; +import type { FontSize } from '@wordpress/global-styles-engine'; + +interface ConfirmDeleteFontSizeDialogProps { + fontSize: FontSize; + isOpen: boolean; + toggleOpen: () => void; + handleRemoveFontSize: ( fontSize: FontSize ) => void; +} function ConfirmDeleteFontSizeDialog( { fontSize, isOpen, toggleOpen, handleRemoveFontSize, -} ) { +}: ConfirmDeleteFontSizeDialogProps ) { const handleConfirm = async () => { toggleOpen(); handleRemoveFontSize( fontSize ); diff --git a/packages/edit-site/src/components/global-styles/font-sizes/confirm-reset-font-sizes-dialog.js b/packages/global-styles-ui/src/font-sizes/confirm-reset-font-sizes-dialog.tsx similarity index 77% rename from packages/edit-site/src/components/global-styles/font-sizes/confirm-reset-font-sizes-dialog.js rename to packages/global-styles-ui/src/font-sizes/confirm-reset-font-sizes-dialog.tsx index fb1bd51ba1479a..eb987f67b9c643 100644 --- a/packages/edit-site/src/components/global-styles/font-sizes/confirm-reset-font-sizes-dialog.js +++ b/packages/global-styles-ui/src/font-sizes/confirm-reset-font-sizes-dialog.tsx @@ -4,13 +4,21 @@ import { __experimentalConfirmDialog as ConfirmDialog } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +interface ConfirmResetFontSizesDialogProps { + text: string; + confirmButtonText: string; + isOpen: boolean; + toggleOpen: () => void; + onConfirm: () => void; +} + function ConfirmResetFontSizesDialog( { text, confirmButtonText, isOpen, toggleOpen, onConfirm, -} ) { +}: ConfirmResetFontSizesDialogProps ) { const handleConfirm = async () => { toggleOpen(); onConfirm(); diff --git a/packages/global-styles-ui/src/font-sizes/font-size-preview.tsx b/packages/global-styles-ui/src/font-sizes/font-size-preview.tsx new file mode 100644 index 00000000000000..35c78298fc9055 --- /dev/null +++ b/packages/global-styles-ui/src/font-sizes/font-size-preview.tsx @@ -0,0 +1,47 @@ +/** + * WordPress dependencies + */ +// @ts-expect-error: Not typed yet. +import { getComputedFluidTypographyValue } from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; +import type { FontSize } from '@wordpress/global-styles-engine'; + +/** + * Internal dependencies + */ +import { useStyle } from '../hooks'; + +interface FontSizePreviewProps { + fontSize: FontSize; +} + +function FontSizePreview( { fontSize }: FontSizePreviewProps ) { + const [ font ] = useStyle< { fontFamily?: string } >( 'typography' ); + + const input = + typeof fontSize?.fluid === 'object' && + fontSize?.fluid?.min && + fontSize?.fluid?.max + ? { + minimumFontSize: fontSize.fluid.min, + maximumFontSize: fontSize.fluid.max, + } + : { + fontSize: fontSize.size, + }; + + const computedFontSize = getComputedFluidTypographyValue( input ); + return ( +
    + { __( 'Aa' ) } +
    + ); +} + +export default FontSizePreview; diff --git a/packages/edit-site/src/components/global-styles/font-sizes/font-size.js b/packages/global-styles-ui/src/font-sizes/font-size.tsx similarity index 73% rename from packages/edit-site/src/components/global-styles/font-sizes/font-size.js rename to packages/global-styles-ui/src/font-sizes/font-size.tsx index cca4a26e1b7368..73b3fdbd35a34d 100644 --- a/packages/edit-site/src/components/global-styles/font-sizes/font-size.js +++ b/packages/global-styles-ui/src/font-sizes/font-size.tsx @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { __, sprintf } from '@wordpress/i18n'; import { __experimentalSpacer as Spacer, @@ -16,19 +15,25 @@ import { } from '@wordpress/components'; import { moreVertical } from '@wordpress/icons'; import { useState, useEffect } from '@wordpress/element'; +import type { + TypographyPreset, + FluidTypographySettings, + FontSize, + FluidTypographyConfig, +} from '@wordpress/global-styles-engine'; /** * Internal dependencies */ -import { unlock } from '../../../lock-unlock'; -import ScreenHeader from '../header'; +import { ScreenHeader } from '../screen-header'; import FontSizePreview from './font-size-preview'; import ConfirmDeleteFontSizeDialog from './confirm-delete-font-size-dialog'; import RenameFontSizeDialog from './rename-font-size-dialog'; -import SizeControl from '../size-control'; +import { SizeControl } from '../size-control'; +import { useSetting } from '../hooks'; +import { unlock } from '../lock-unlock'; const { Menu } = unlock( componentsPrivateApis ); -const { useGlobalSetting } = unlock( blockEditorPrivateApis ); function FontSize() { const [ isDeleteConfirmOpen, setIsDeleteConfirmOpen ] = useState( false ); @@ -39,17 +44,20 @@ function FontSize() { goBack, } = useNavigator(); - const [ fontSizes, setFontSizes ] = useGlobalSetting( - 'typography.fontSizes' - ); - - const [ globalFluid ] = useGlobalSetting( 'typography.fluid' ); + const [ fontSizes, setFontSizes ] = useSetting< + Record< string, TypographyPreset[] > | undefined + >( 'typography.fontSizes' ); + const [ globalFluid ] = useSetting< + boolean | FluidTypographySettings | undefined + >( 'typography.fluid' ); // Get the font sizes from the origin, default to empty array. - const sizes = fontSizes[ origin ] ?? []; + const sizes = fontSizes?.[ origin as string ] ?? []; // Get the font size by slug. - const fontSize = sizes.find( ( size ) => size.slug === slug ); + const fontSize: FontSize | undefined = sizes.find( + ( size ) => size.slug === slug + ); // Navigate to the font sizes list if the font size is not available. useEffect( () => { @@ -69,19 +77,19 @@ function FontSize() { // Whether custom fluid values are used. const isCustomFluid = typeof fontSize?.fluid === 'object'; - const handleNameChange = ( value ) => { + const handleNameChange = ( value: string ) => { updateFontSize( 'name', value ); }; - const handleFontSizeChange = ( value ) => { + const handleFontSizeChange = ( value: string | undefined ) => { updateFontSize( 'size', value ); }; - const handleFluidChange = ( value ) => { + const handleFluidChange = ( value: boolean ) => { updateFontSize( 'fluid', value ); }; - const handleCustomFluidValues = ( value ) => { + const handleCustomFluidValues = ( value: boolean ) => { if ( value ) { // If custom values are used, init the values with the current ones. updateFontSize( 'fluid', { @@ -94,15 +102,19 @@ function FontSize() { } }; - const handleMinChange = ( value ) => { - updateFontSize( 'fluid', { ...fontSize.fluid, min: value } ); + const handleMinChange = ( value: string | undefined ) => { + const fluid: FluidTypographyConfig = + typeof fontSize.fluid === 'object' ? fontSize.fluid : {}; + updateFontSize( 'fluid', { ...fluid, min: value } ); }; - const handleMaxChange = ( value ) => { - updateFontSize( 'fluid', { ...fontSize.fluid, max: value } ); + const handleMaxChange = ( value: string | undefined ) => { + const fluid: FluidTypographyConfig = + typeof fontSize.fluid === 'object' ? fontSize.fluid : {}; + updateFontSize( 'fluid', { ...fluid, max: value } ); }; - const updateFontSize = ( key, value ) => { + const updateFontSize = ( key: string, value: any ) => { const newFontSizes = sizes.map( ( size ) => { if ( size.slug === slug ) { return { ...size, [ key ]: value }; // Create a new object with updated key @@ -112,7 +124,7 @@ function FontSize() { setFontSizes( { ...fontSizes, - [ origin ]: newFontSizes, + [ origin as string ]: newFontSizes, } ); }; @@ -120,7 +132,7 @@ function FontSize() { const newFontSizes = sizes.filter( ( size ) => size.slug !== slug ); setFontSizes( { ...fontSizes, - [ origin ]: newFontSizes, + [ origin as string ]: newFontSizes, } ); }; @@ -150,7 +162,7 @@ function FontSize() { ) } - + @@ -244,12 +260,20 @@ function FontSize() { <> diff --git a/packages/edit-site/src/components/global-styles/font-sizes/font-sizes-count.js b/packages/global-styles-ui/src/font-sizes/font-sizes-count.tsx similarity index 95% rename from packages/edit-site/src/components/global-styles/font-sizes/font-sizes-count.js rename to packages/global-styles-ui/src/font-sizes/font-sizes-count.tsx index fb23a38fe43bc2..42e2898db36949 100644 --- a/packages/edit-site/src/components/global-styles/font-sizes/font-sizes-count.js +++ b/packages/global-styles-ui/src/font-sizes/font-sizes-count.tsx @@ -13,7 +13,7 @@ import { Icon, chevronLeft, chevronRight } from '@wordpress/icons'; /** * Internal dependencies */ -import Subtitle from '../subtitle'; +import { Subtitle } from '../subtitle'; import { NavigationButtonAsItem } from '../navigation-button'; function FontSizes() { diff --git a/packages/edit-site/src/components/global-styles/font-sizes/font-sizes.js b/packages/global-styles-ui/src/font-sizes/font-sizes.tsx similarity index 83% rename from packages/edit-site/src/components/global-styles/font-sizes/font-sizes.js rename to packages/global-styles-ui/src/font-sizes/font-sizes.tsx index ce694a5020908f..d9126686cbf646 100644 --- a/packages/edit-site/src/components/global-styles/font-sizes/font-sizes.js +++ b/packages/global-styles-ui/src/font-sizes/font-sizes.tsx @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { __, sprintf, isRTL } from '@wordpress/i18n'; import { privateApis as componentsPrivateApis, @@ -21,19 +20,28 @@ import { chevronRight, } from '@wordpress/icons'; import { useState } from '@wordpress/element'; +import type { FontSize } from '@wordpress/global-styles-engine'; /** * Internal dependencies */ -import { unlock } from '../../../lock-unlock'; -import Subtitle from '../subtitle'; +import { Subtitle } from '../subtitle'; import { NavigationButtonAsItem } from '../navigation-button'; import { getNewIndexFromPresets } from '../utils'; -import ScreenHeader from '../header'; +import { ScreenHeader } from '../screen-header'; import ConfirmResetFontSizesDialog from './confirm-reset-font-sizes-dialog'; +import { useSetting } from '../hooks'; +import { unlock } from '../lock-unlock'; const { Menu } = unlock( componentsPrivateApis ); -const { useGlobalSetting } = unlock( blockEditorPrivateApis ); + +interface FontSizeGroupProps { + label: string; + origin: string; + sizes: FontSize[]; + handleAddFontSize: () => void; + handleResetFontSizes?: () => void; +} function FontSizeGroup( { label, @@ -41,7 +49,7 @@ function FontSizeGroup( { sizes, handleAddFontSize, handleResetFontSizes, -} ) { +}: FontSizeGroupProps ) { const [ isResetDialogOpen, setIsResetDialogOpen ] = useState( false ); const toggleResetDialog = () => setIsResetDialogOpen( ! isResetDialogOpen ); @@ -57,7 +65,7 @@ function FontSizeGroup( { return ( <> - { isResetDialogOpen && ( + { handleResetFontSizes && isResetDialogOpen && ( { label } - + { origin === 'custom' && (