@marp-team/marpit
Version:
The skinny framework for creating slide deck from Markdown
234 lines (192 loc) • 7.36 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _postcss = _interopRequireDefault(require("postcss"));
var _advanced_background = _interopRequireDefault(require("./postcss/advanced_background"));
var _replace = _interopRequireDefault(require("./postcss/import/replace"));
var _rollup = _interopRequireDefault(require("./postcss/import/rollup"));
var _suppress = _interopRequireDefault(require("./postcss/import/suppress"));
var _pagination = _interopRequireDefault(require("./postcss/pagination"));
var _printable = _interopRequireDefault(require("./postcss/printable"));
var _prepend = _interopRequireDefault(require("./postcss/pseudo_selector/prepend"));
var _replace2 = _interopRequireDefault(require("./postcss/pseudo_selector/replace"));
var _theme = _interopRequireDefault(require("./theme"));
var _scaffold = _interopRequireDefault(require("./theme/scaffold"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Marpit theme set class.
*/
class ThemeSet {
constructor() {
/**
* An instance of default theme.
*
* While running {@link ThemeSet#pack}, ThemeSet will use this theme when
* the definition of theme directive or the theme with specified name is not
* found.
*
* By default, Marpit does not provide default theme (`undefined`).
*
* @type {Theme|undefined}
*/
this.default = undefined;
Object.defineProperty(this, 'themeMap', {
value: new Map()
});
}
/**
* Return the number of themes.
*
* @type {number}
* @readonly
*/
get size() {
return this.themeMap.size;
}
/**
* Add theme CSS from string.
*
* @param {string} css The theme CSS string.
* @returns {Theme} A created {@link Theme} instance.
* @throws Will throw an error if the theme name is not specified by `@theme`.
*/
add(css) {
const theme = _theme.default.fromCSS(css);
this.addTheme(theme);
return theme;
}
/**
* Add theme instance.
*
* @param {Theme} theme The theme instnace.
* @throws Will throw an error if the theme name is not specified.
*/
addTheme(theme) {
if (!(theme instanceof _theme.default)) throw new Error('ThemeSet can add only an instance of Theme.');
if (typeof theme.name !== 'string') throw new Error('An instance of Theme requires name.');
this.themeMap.set(theme.name, theme);
}
/**
* Removes all themes from a {@link themeSet} object.
*/
clear() {
return this.themeMap.clear();
}
/**
* Remove a specific named theme from a {@link themeSet} object.
*
* @param {string} name The theme name to delete.
* @returns {boolean} Returns `true` if a theme in current {@link ThemeSet}
* existed and has been removed, or `false` if the theme does not exist.
*/
delete(name) {
return this.themeMap.delete(name);
}
/**
* Returns a specific named theme.
*
* @param {string} name The theme name to get.
* @param {boolean} [fallback=false] If true, return instance's default theme
* or scaffold theme when specified theme cannot find.
* @returns {Theme|undefined} Returns specified or fallbacked theme, or
* `undefined` if `fallback` is false and the specified theme has not
* existed.
*/
get(name, fallback = false) {
const theme = this.themeMap.get(name);
return fallback ? theme || this.default || _scaffold.default : theme;
}
/**
* Returns the value of property from a specified theme. It considers
* `@import` rules in getting property value.
*
* It will fallback the reference object into the instance's default theme or
* scaffold theme when the specified theme is undefined.
*
* @param {string|Theme} theme The theme name or instance.
* @param {string} prop The property name to get.
*/
getThemeProp(theme, prop, importedThemes = []) {
let importedProps = [];
const themeInstance = theme instanceof _theme.default ? theme : this.get(theme);
if (themeInstance) {
const {
name
} = themeInstance;
if (importedThemes.includes(name)) throw new Error(`Circular "${name}" theme import is detected.`);
importedProps = themeInstance.importRules.map(r => {
const importTheme = this.get(r.value);
return importTheme ? this.getThemeProp(importTheme, prop, [...importedThemes, name].filter(n => n)) : undefined;
}).filter(r => r).reverse();
}
return [themeInstance && themeInstance[prop], ...importedProps, this.default && this.default[prop], _scaffold.default[prop]].find(t => t);
}
/**
* Returns a boolean indicating whether a specific named theme exists or not.
*
* @param {string} name The theme name.
* @returns {boolean} Returns `true` if a specific named theme exists,
* otherwise `false`.
*/
has(name) {
return this.themeMap.has(name);
}
/**
* Convert registered theme CSS into usable in the rendered markdown by
* {@link Marpit#render}.
*
* You should use {@link Marpit#render} unless there is some particular
* reason.
*
* @param {string} name The theme name. It will use the instance's default
* theme or scaffold theme when a specific named theme does not exist.
* @param {Object} [opts] The option object passed by {@link Marpit#render}.
* @param {string} [opts.after] A CSS string to append into after theme.
* @param {string} [opts.before] A CSS string to prepend into before theme.
* @param {Element[]} [opts.containers] Container elements wrapping whole
* slide deck.
* @param {boolean} [opts.printable] Make style printable to PDF.
* @param {boolean} [opts.inlineSVG] Apply a hierarchy of inline SVG to CSS
* selector by setting `true`. _(Experimental)_
* @return {string} The converted CSS string.
*/
pack(name, opts = {}) {
const slideElements = [{
tag: 'section'
}];
const theme = this.get(name, true);
if (opts.inlineSVG) slideElements.unshift({
tag: 'svg'
}, {
tag: 'foreignObject'
});
const additionalCSS = css => {
if (!css) return undefined;
try {
return (0, _postcss.default)([(0, _suppress.default)(this)]).process(css).css;
} catch (e) {
return undefined;
}
};
const after = additionalCSS(opts.after);
const before = additionalCSS(opts.before);
const packer = (0, _postcss.default)([before && (css => css.first.before(before)), after && (css => css.last.after(after)), _rollup.default, (0, _replace.default)(this), opts.printable && (0, _printable.default)({
width: this.getThemeProp(theme, 'width'),
height: this.getThemeProp(theme, 'height')
}), theme !== _scaffold.default && (css => css.first.before(_scaffold.default.css)), opts.inlineSVG && _advanced_background.default, _pagination.default, _prepend.default, (0, _replace2.default)(opts.containers, slideElements), _rollup.default].filter(p => p));
return packer.process(theme.css).css;
}
/**
* Returns a `Iterator` object that contains registered themes to current
* instance.
*
* @returns {Iterator.<Theme>}
*/
themes() {
return this.themeMap.values();
}
}
var _default = ThemeSet;
exports.default = _default;