* #378 add emoji suggestion * #378 use lazy load for nodeEmoji * #378 apply remark styles only for light theme * #378 add dark theme * #378 fix test * #378 use permanent class names * #378 flip if else for readability
This commit is contained in:
committed by
Umputun
parent
3c12fde0f8
commit
17be003652
@@ -0,0 +1 @@
|
||||
.env
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
declare module '*.module.pcss' {
|
||||
interface ClassNames {
|
||||
[className: string]: string;
|
||||
}
|
||||
const classNames: ClassNames;
|
||||
export = classNames;
|
||||
}
|
||||
+4
@@ -19,6 +19,10 @@ declare module 'preact/src/jsx' {
|
||||
'md-link': any;
|
||||
'md-unordered-list': any;
|
||||
'md-ordered-list': any;
|
||||
'text-expander': {
|
||||
ref: any;
|
||||
children: any;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export const StaticStore: StaticStoreType = {
|
||||
simple_view: false,
|
||||
anon_vote: false,
|
||||
email_notifications: false,
|
||||
emoji_enabled: false,
|
||||
},
|
||||
query: querySettings as QuerySettingsType,
|
||||
};
|
||||
|
||||
@@ -115,6 +115,7 @@ export interface Config {
|
||||
simple_view: boolean;
|
||||
anon_vote: boolean;
|
||||
email_notifications: boolean;
|
||||
emoji_enabled: boolean;
|
||||
}
|
||||
|
||||
export interface RemarkConfig {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { SubscribeByRSS } from './__subscribe-by-rss';
|
||||
|
||||
import MarkdownToolbar from './markdown-toolbar';
|
||||
import TextareaAutosize from './textarea-autosize';
|
||||
import { TextExpander } from './text-expander';
|
||||
|
||||
let textareaId = 0;
|
||||
|
||||
@@ -144,7 +145,7 @@ export class CommentForm extends Component<Props, State> {
|
||||
}
|
||||
|
||||
send(e: Event) {
|
||||
const text = this.state.text;
|
||||
const text = this.textAreaRef.current ? this.textAreaRef.current.getValue() : this.state.text;
|
||||
const props = this.props;
|
||||
|
||||
if (e) e.preventDefault();
|
||||
@@ -156,7 +157,7 @@ export class CommentForm extends Component<Props, State> {
|
||||
this.setState({ preview: null, text: '' });
|
||||
}
|
||||
|
||||
this.setState({ isDisabled: true, isErrorShown: false });
|
||||
this.setState({ isDisabled: true, isErrorShown: false, text });
|
||||
|
||||
props
|
||||
.onSubmit(text, pageTitle || document.title)
|
||||
@@ -172,11 +173,11 @@ export class CommentForm extends Component<Props, State> {
|
||||
}
|
||||
|
||||
getPreview() {
|
||||
const text = this.state.text;
|
||||
const text = this.textAreaRef.current ? this.textAreaRef.current.getValue() : this.state.text;
|
||||
|
||||
if (!text || !text.trim()) return;
|
||||
|
||||
this.setState({ isErrorShown: false, errorMessage: null });
|
||||
this.setState({ isErrorShown: false, errorMessage: null, text });
|
||||
|
||||
this.props
|
||||
.getPreview(text)
|
||||
@@ -369,21 +370,22 @@ export class CommentForm extends Component<Props, State> {
|
||||
</div>
|
||||
)}
|
||||
<div className="comment-form__field-wrapper">
|
||||
<TextareaAutosize
|
||||
id={this.textareaId}
|
||||
onPaste={this.onPaste}
|
||||
ref={this.textAreaRef}
|
||||
className="comment-form__field"
|
||||
placeholder="Your comment here"
|
||||
value={text}
|
||||
maxLength={maxLength}
|
||||
onInput={this.onInput}
|
||||
onKeyDown={this.onKeyDown}
|
||||
disabled={isDisabled}
|
||||
autofocus={!!props.autofocus}
|
||||
spellcheck={true}
|
||||
/>
|
||||
|
||||
<TextExpander>
|
||||
<TextareaAutosize
|
||||
id={this.textareaId}
|
||||
onPaste={this.onPaste}
|
||||
ref={this.textAreaRef}
|
||||
className="comment-form__field"
|
||||
placeholder="Your comment here"
|
||||
value={text}
|
||||
maxLength={maxLength}
|
||||
onInput={this.onInput}
|
||||
onKeyDown={this.onKeyDown}
|
||||
disabled={isDisabled}
|
||||
autofocus={!!props.autofocus}
|
||||
spellcheck={true}
|
||||
/>
|
||||
</TextExpander>
|
||||
{charactersLeft < 100 && <span className="comment-form__counter">{charactersLeft}</span>}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
.suggester {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 30;
|
||||
min-width: 180px;
|
||||
padding: 0;
|
||||
margin: 24px 0 0;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
border: 1px solid #dfe2e5;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 5px rgba(27, 31, 35, 0.15);
|
||||
}
|
||||
|
||||
.suggesterDark {
|
||||
background: #22201c;
|
||||
color: #ddd;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
|
||||
.suggesterItem {
|
||||
display: block;
|
||||
padding: 4px 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid #dfe2e5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.suggesterItemDark {
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.suggesterItem:hover,
|
||||
.suggesterItem[aria-selected='true'] {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
background-color: rgba(37, 156, 154, 0.6);
|
||||
}
|
||||
|
||||
.suggesterItem:first-child {
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
.suggesterItem:last-child {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.emojiResult {
|
||||
margin-right: 0;
|
||||
display: inline-block;
|
||||
line-height: 20px;
|
||||
font-size: 20px;
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/** @jsx createElement */
|
||||
import { createElement, Fragment, render, FunctionalComponent } from 'preact';
|
||||
import { StaticStore } from '@app/common/static_store';
|
||||
import { useEffect, useRef } from 'preact/hooks';
|
||||
import '@github/text-expander-element';
|
||||
import styles from './text-expander.module.pcss';
|
||||
import cx from 'classnames';
|
||||
import { Theme } from '@app/common/types';
|
||||
import useTheme from '@app/hooks/useTheme';
|
||||
|
||||
type Emoji = {
|
||||
key: string;
|
||||
emoji: string;
|
||||
};
|
||||
|
||||
function SuggestionList({ items, theme }: { items: Array<Emoji>; theme: Theme }) {
|
||||
const isDarkTheme = theme === `dark`;
|
||||
const suggesterClass = cx(styles.suggester, { [styles.suggesterDark]: isDarkTheme });
|
||||
const suggesterItemClass = cx(styles.suggesterItem, { [styles.suggesterItemDark]: isDarkTheme });
|
||||
return (
|
||||
<ul className={suggesterClass}>
|
||||
{items.map(({ key, emoji }: Emoji) => {
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/role-has-required-aria-props
|
||||
<li role="option" className={suggesterItemClass} data-value={key}>
|
||||
<span className={styles.emojiResult}>{emoji}</span> {key}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
function searchEmoji(key: string, text: string, theme: Theme) {
|
||||
return import(/* webpackChunkName: "node-emoji" */ `node-emoji`)
|
||||
.then(nodeEmoji => {
|
||||
if (key === ':') {
|
||||
const emojiList = nodeEmoji.search(text);
|
||||
if (emojiList.length === 0) {
|
||||
return Promise.resolve({ matched: false });
|
||||
}
|
||||
const fragment = document.createDocumentFragment();
|
||||
render(<SuggestionList theme={theme} items={emojiList.slice(0, 5)} />, fragment);
|
||||
return Promise.resolve({ matched: true, fragment: fragment.firstChild });
|
||||
}
|
||||
return Promise.resolve({ matched: false });
|
||||
})
|
||||
.catch(() => Promise.resolve({ matched: false }));
|
||||
}
|
||||
|
||||
type ChangeListerEvent = Event & {
|
||||
detail: {
|
||||
key: string;
|
||||
text: string;
|
||||
provide(value: Promise<{ matched: boolean }>): void;
|
||||
};
|
||||
};
|
||||
|
||||
type ValueListerEvent = Event & {
|
||||
detail: {
|
||||
key: string;
|
||||
value: string;
|
||||
item: HTMLLIElement;
|
||||
};
|
||||
};
|
||||
|
||||
export const TextExpander: FunctionalComponent = ({ children }) => {
|
||||
const expanderRef = useRef<HTMLElement>();
|
||||
const theme = useTheme();
|
||||
useEffect(() => {
|
||||
if (expanderRef.current) {
|
||||
const expander = expanderRef.current;
|
||||
expander.setAttribute(`keys`, ':');
|
||||
const textExpanderChangeLister: EventListener = (event: Event) => {
|
||||
const { provide, key, text } = (event as ChangeListerEvent).detail;
|
||||
provide(searchEmoji(key, text, theme));
|
||||
};
|
||||
const textExpanderValueListener = (event: Event) => {
|
||||
const { key, item } = (event as ValueListerEvent).detail;
|
||||
if (key === ':') {
|
||||
(event as ValueListerEvent).detail.value = `:${item.dataset.value}:`;
|
||||
}
|
||||
};
|
||||
expander.addEventListener('text-expander-change', textExpanderChangeLister);
|
||||
expander.addEventListener('text-expander-value', textExpanderValueListener);
|
||||
return () => {
|
||||
expander.removeEventListener('text-expander-change', textExpanderChangeLister);
|
||||
expander.removeEventListener('text-expander-value', textExpanderValueListener);
|
||||
};
|
||||
}
|
||||
return () => {};
|
||||
}, [theme]);
|
||||
if (StaticStore.config.emoji_enabled) {
|
||||
return <text-expander ref={expanderRef}>{children}</text-expander>;
|
||||
}
|
||||
|
||||
return <Fragment>{children}</Fragment>;
|
||||
};
|
||||
@@ -58,7 +58,9 @@ export default class TextareaAutosize extends Component<Props> {
|
||||
onRef(node: HTMLTextAreaElement) {
|
||||
this.textareaRef = node;
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.textareaRef ? this.textareaRef.value : '';
|
||||
}
|
||||
autoResize() {
|
||||
if (this.textareaRef) {
|
||||
this.textareaRef.style.height = '';
|
||||
|
||||
@@ -24,5 +24,6 @@ beforeEach(() => {
|
||||
simple_view: false,
|
||||
anon_vote: false,
|
||||
email_notifications: false,
|
||||
emoji_enabled: true,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ module.exports = {
|
||||
testRegex: '(\\.|/)(test|spec)\\.(j|t)s(x?)$',
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
||||
moduleNameMapper: {
|
||||
'\\.module.pcss': `identity-obj-proxy`,
|
||||
'\\.scss$': '<rootDir>/app/testUtils/mockStyles.js',
|
||||
'@app/(.*)': '<rootDir>/app/$1',
|
||||
'^react$': 'preact/compat',
|
||||
|
||||
Generated
+62
@@ -1137,11 +1137,24 @@
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@github/combobox-nav": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-1.0.1.tgz",
|
||||
"integrity": "sha512-5I/jWX/ymlZ0zIbBLZVkZXE80cYqwnNRkFOw3DrwklEqHouTyNWrXUn9z2kAQL4aSKEYqLbyZbTyCB59TYcJjg=="
|
||||
},
|
||||
"@github/markdown-toolbar-element": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@github/markdown-toolbar-element/-/markdown-toolbar-element-1.1.0.tgz",
|
||||
"integrity": "sha512-QBTFBSsfreBiS0h//3NL0D7qC5rsU2M9kwahKQWna01cbVMmgismW/PZlaizub+0Q3Yw2VBYAr08xJp/v0BiQQ=="
|
||||
},
|
||||
"@github/text-expander-element": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-1.0.1.tgz",
|
||||
"integrity": "sha512-QAOvzcQ6mA/k9P2NSk+1pjLeL5XD86qZlQY4U13uVe4Pitb6xh08hFgUgZpDUeUkm0z3bphMFN/czuP/58/6zg==",
|
||||
"requires": {
|
||||
"@github/combobox-nav": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@jest/console": {
|
||||
"version": "24.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz",
|
||||
@@ -1758,6 +1771,11 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/classnames": {
|
||||
"version": "2.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.9.tgz",
|
||||
"integrity": "sha512-MNl+rT5UmZeilaPxAVs6YaPC2m6aA8rofviZbhbxpPpl61uKodfdQVsBtgJGTqGizEf02oW3tsVe7FYB8kK14A=="
|
||||
},
|
||||
"@types/core-js": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/core-js/-/core-js-2.5.2.tgz",
|
||||
@@ -1867,6 +1885,11 @@
|
||||
"integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-emoji": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-emoji/-/node-emoji-1.8.1.tgz",
|
||||
"integrity": "sha512-0fRfA90FWm6KJfw6P9QGyo0HDTCmthZ7cWaBQndITlaWLTZ6njRyKwrwpzpg+n6kBXBIGKeUHEQuBx7bphGJkA=="
|
||||
},
|
||||
"@types/normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
@@ -3579,6 +3602,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
|
||||
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
|
||||
@@ -4698,6 +4726,12 @@
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||
"dev": true
|
||||
},
|
||||
"duplexer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||
@@ -6771,6 +6805,12 @@
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"harmony-reflect": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.1.tgz",
|
||||
"integrity": "sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA==",
|
||||
"dev": true
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
@@ -7249,6 +7289,15 @@
|
||||
"postcss": "^7.0.14"
|
||||
}
|
||||
},
|
||||
"identity-obj-proxy": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz",
|
||||
"integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"harmony-reflect": "^1.4.6"
|
||||
}
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
|
||||
@@ -10182,6 +10231,11 @@
|
||||
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.toarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
|
||||
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE="
|
||||
},
|
||||
"lodash.unescape": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
|
||||
@@ -10731,6 +10785,14 @@
|
||||
"lower-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node-emoji": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
|
||||
"integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
|
||||
"requires": {
|
||||
"lodash.toarray": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^3.2.0",
|
||||
"document-register-element": "^1.14.3",
|
||||
"dotenv": "^8.2.0",
|
||||
"enzyme": "^3.10.0",
|
||||
"enzyme-adapter-preact-pure": "^2.1.0",
|
||||
"es-check": "^5.1.0",
|
||||
@@ -63,6 +64,7 @@
|
||||
"file-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"husky": "^3.0.9",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^24.9.0",
|
||||
"jest-enzyme": "^7.1.1",
|
||||
"jest-extended": "^0.11.2",
|
||||
@@ -94,11 +96,16 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@github/markdown-toolbar-element": "^1.1.0",
|
||||
"@github/text-expander-element": "^1.0.1",
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/node-emoji": "^1.8.1",
|
||||
"@webcomponents/custom-elements": "^1.3.0",
|
||||
"bem-react-helper": "^1.1.2",
|
||||
"classnames": "^2.2.6",
|
||||
"core-js": "^3.2.1",
|
||||
"focus-visible": "^5.0.2",
|
||||
"intersection-observer": "^0.7.0",
|
||||
"node-emoji": "^1.10.0",
|
||||
"preact": "^10.0.1",
|
||||
"react-redux": "^7.1.1",
|
||||
"redux": "^4.0.4",
|
||||
|
||||
+36
-19
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
require('dotenv').config();
|
||||
const path = require('path');
|
||||
|
||||
const webpack = require('webpack');
|
||||
@@ -27,7 +27,7 @@ console.log(`REMARK_ENV = ${remarkUrl}`);
|
||||
* so we have to exclude from ignore these modules
|
||||
*/
|
||||
function getExcluded() {
|
||||
const modules = ['@github/markdown-toolbar-element'];
|
||||
const modules = ['@github/markdown-toolbar-element', '@github/text-expander-element', '@github/combobox-nav'];
|
||||
const exclude = new RegExp(`node_modules\\/(?!(${modules.map(m => m.replace(/\//g, '\\/')).join('|')})\\/).*`);
|
||||
|
||||
return {
|
||||
@@ -38,24 +38,23 @@ function getExcluded() {
|
||||
// console.log(getExcluded())
|
||||
// process.exit(1)
|
||||
|
||||
const commonStyleLoaders = [
|
||||
'css-loader',
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
require('postcss-for'),
|
||||
require('postcss-simple-vars'),
|
||||
require('postcss-nested'),
|
||||
require('postcss-calc'),
|
||||
require('autoprefixer')({ overrideBrowserslist: ['> 1%'] }),
|
||||
require('postcss-url')({ url: 'inline', maxSize: 5 }),
|
||||
require('postcss-wrap')({ selector: `#${NODE_ID}` }),
|
||||
require('postcss-csso'),
|
||||
],
|
||||
},
|
||||
const postCssLoader = wrap => ({
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
require('postcss-for'),
|
||||
require('postcss-simple-vars'),
|
||||
require('postcss-nested'),
|
||||
require('postcss-calc'),
|
||||
require('autoprefixer')({ overrideBrowserslist: ['> 1%'] }),
|
||||
require('postcss-url')({ url: 'inline', maxSize: 5 }),
|
||||
wrap ? require('postcss-wrap')({ selector: `#${NODE_ID}` }) : false,
|
||||
require('postcss-csso'),
|
||||
].filter(plugin => plugin),
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const commonStyleLoaders = ['css-loader', postCssLoader(true)];
|
||||
|
||||
const babelConfigPath = path.resolve(__dirname, './.babelrc.js');
|
||||
|
||||
@@ -104,6 +103,24 @@ module.exports = () => ({
|
||||
...commonStyleLoaders,
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.module\.pcss$/,
|
||||
use: [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
mode: `local`,
|
||||
localIdentName: `${NODE_ID}__[name]__[local]`,
|
||||
},
|
||||
},
|
||||
},
|
||||
postCssLoader(false),
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|jpeg|gif|svg)$/,
|
||||
use: {
|
||||
|
||||
Reference in New Issue
Block a user