1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/mirrors-material-components-web

Клонировать/Скачать
authoring-components.md 55 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 02.06.2025 13:26 9c60297

Создание компонентов

Документ служит справочным материалом для разработки компонентов как напрямую для MDC Web, так и для внешних компонентов, которые хотят взаимодействовать с экосистемой MDC Web.> Пожалуйста, обратите внимание, что, так как этот проект находится на ранних стадиях разработки, эти практики могут быть изменены. Они устаканятся по мере приближения к полной релизации. - Создание компонентов - Для кого предназначен этот документ - Как создать компонент - Начните с простого прототипа компонента - Определите взаимодействия с окружением - Создайте интерфейс адаптера - Переработайте существующий код в основу - Создайте компонент на основе этой основы, предоставляя адаптер - Что делает хороший компонент - Полностью протестированный код - Тщательно документированный и строго версионированный интерфейс адаптера - Доступность - Поддержка RTL - Поддержка тем - Общие лучшие практики - Делайте то, что ожидает пользователь - Проектируйте интерфейсы адаптеров так, чтобы они были простыми и интуитивно понятными - Не ссылайтесь на объекты окружения в коде основы - Удаляйте все ссылки при разрушении - Создание компонентов для MDC Web - Структура файлов - Лицензионные условия - Scss - Отделяйте повторно используемые переменные и миксины от основного scss - Следуйте паттерну BEM - Используйте mdc-theme для тем - Используйте mdc-rtl для поддержки RTL - Javascript - Определите статический метод attachTo(root) для каждого компонента - Определите getter defaultAdapter для каждого основания - Определите все экспортированные CSS классы, строки и числа как константы основания. - Расширяйте компоненты и основания от mdc-base классов.](#расширяйте-компоненты-и-основания-из-базовых-классов-mdc-базы)](#расширение-компонентов-и-фундаментов-из-базовых-классов-mdc-базы) - Пакеты должны быть зарегистрированы с нашей системой сборки и с material-components-web pkg - Совместимость с TypeScript - Тестирование - Проверка адаптеров фундаментов - Использование вспомогательных методов - Использование bel для DOM-фикстур - Всегда очищайте DOM после каждого теста - Проверка адаптеров с помощью testdouble

Для кого предназначен этот документПервые две секции этого документа описывают общие руководства по тому, как следует мыслить при создании компонента, а также критерии, определяющие хороший компонент. Любой, кто интересуется созданием компонентов как для MDC Web, так и для внешних компонентов, которые хорошо интегрируются в экосистему MDC Web, найдет это полезным. Третья секция посвящена созданию компонентов конкретно для MDC Web и предназначена для тех, кто хочет внести прямой вклад в проект.

Обратите внимание, что этот документ предполагает, что вы знакомы с библиотекой и ее архитектурой. Если это не так, мы рекомендуем прочитать это сначала. Если вы новичок в проекте, мы рекомендуем начать с нашего руководства по началу работы.

Как создать компонент

Эта секция описывает процесс мышления при создании новых компонентов для MDC Web. Она вдохновлена статьей React Thinking in React.

Начиная с нуля и сразу переходя к реализации компонента/адаптера/фундамента может быть устрашающим, а в худшем случае — полностью невозможным с точки зрения продуктивности и экспериментов. Часто вы захотите создать прототип компонента самым прямым способом, а затем постепенно вернуться к созданию фундамента и адаптера. Мы обычно следуем следующим шагам.Чтобы продемонстрировать этот подход, мы создадим красно-синий переключатель, очень простой переключатель, который переключается между красным фоном с синим текстом и наоборот. Хотя это не компонент Material Design, он демонстрирует концепции того, как следует мыслить при создании компонентов для MDC Web.

Начните с простого прототипа компонента

Когда вы начинаете работу над новым компонентом, начните с создания прототипа с использованием чистого HTML/CSS/JavaScript, не беспокоясь о фундаменте или адаптерах. Ниже приведен прототип кода для нашего redblue-toggle, который вы также можете посмотреть на Codepen.

СОВЕТ: При создании своих собственных компонентов вы можете использовать этот шаблон Codepen в качестве отправной точки.

Начните с экспериментирования с структурой DOM и написанием простого прототипа компонента для тестирования динамической функциональности.

<div class="redblue-toggle" role="button" aria-pressed="false">
  Переключить <span class="redblue-toggle__color">синий</span>
</div>
class RedblueTogglePrototype {
  get toggled() {
    return this.root.getAttribute('aria-pressed') === 'true';
  }

  set toggled(toggled) {
    this.toggle(toggled);
  }

  constructor(root) {
    this.root = root;
    this.clickHandler = () => this.toggle();
    this.initialize();
  }

  initialize() {
    this.root.addEventListener('click', this.clickHandler);
  }

  destroy() {
    this.root.removeEventListener('click', this.clickHandler);
  }
}
```  toggle(isToggled = undefined) {
    const wasToggledExplicitlySet = isToggled === Boolean(isToggled);
    const toggled = wasToggledExplicitlySet ? isToggled : !this.toggled;
    const toggleColorEl = this.root.querySelector<HTMLElement>('.redblue-toggle__color');
    let toggleColor;

    this.root.setAttribute('aria-pressed', String(toggled));
    if (toggled) {
      toggleColor = 'Красный';
      this.root.classList.add('redblue-toggle--toggled');
    } else {
      toggleColor = 'Синий';
      this.root.classList.remove('redblue-toggle--toggled');
    }
    toggleColorEl.textContent = toggleColor;
  }
}

new RedblueTogglePrototype(document.querySelector<HTMLElement>('.redblue-toggle'));

Обратите внимание, как компонент JavaScript не ссылается на MDC Web ни в каком виде, и не имеет никакого понимания о фундаментах или адаптерах. Исключив эту работу, вы можете быстро экспериментировать с вашим компонентом, внедряя изменения быстро и легко. Тем не менее, способ прототипирования компонента выглядит очень похожим на способ, которым будет построен компонент MDC Web.

Определите взаимодействия с окружением

Как только вы удовлетворены прототипом, следующим шагом является определение того, какие функции будут требовать проксирования через адаптер. Любые прямые взаимодействия с окружением будут требовать проксирования, чтобы наши фундаменты могли интегрироваться во всех фреймворках по всему веб-платформе.> Как упоминалось в нашей документации по архитектуре, термин окружение относится к контексту, в котором компонент используется. Это может быть браузер, сервер, на котором компонент отображается, виртуальная среда DOM или даже мобильное приложение в случае технологий, таких как React-Native. Для redblue-toggle легко заметить все случаи взаимодействия с окружением хоста: это происходит каждый раз, когда мы читаем или записываем данные в узел root.- Обновление aria-pressed при переключении через setAttribute

  • Обновление классов узла root при переключении через classList.{add,remove}
  • Установка textContent элемента индикатора цвета при переключении
  • Добавление/удаление слушателей событий на узле root внутри initialize()/destroy() соответственно

В других случаях взаимодействие с окружением хоста может быть не очевидным, например, window.addEventListener('resize', ...). Эти случаи также являются примерами взаимодействия с окружением хоста и должны учитываться.

Создание интерфейса адаптера

Теперь, когда взаимодействия с окружением хоста определены, можно выделить интерфейс адаптера внутри нашего существующего компонента.

class RedblueTogglePrototype {
  get toggled() {
    return SOMEHOW_GET_ATTRIBUTE('aria-pressed') === 'true';
  }

  set toggled(toggled) {
    this.toggle(toggled);
  }

  constructor(root) {
    this.root = root;
    this.clickHandler = () => this.toggle();
    this.initialize();
  }

  initialize() {
    this.root.addEventListener('click', this.clickHandler);
  }

  destroy() {
    this.root.removeEventListener('click', this.clickHandler);
  }

  toggle(isToggled = undefined) {
    const wasToggledExplicitlySet = isToggled === Boolean(isToggled);
    const toggled = wasToggledExplicitlySet ? isToggled : !this.toggled;

    let toggleColor;

    SOMEHOW_SET_ATTRIBUTE('aria-pressed', String(toggled));
    if (toggled) {
      toggleColor = 'Red';
      SOMEHOW_ADD_CLASS('redblue-toggle--toggled');
    } else {
      toggleColor = 'Blue';
      SOMEHOW_REMOVE_CLASS('redblue-toggle--toggled');
    }
    SOMEHOW_UPDATE_TOGGLE_COLOR_TEXT_CONTENT(toggleColor);
  }
}
```В приведенном выше коде все взаимодействия с окружением хоста заменены на фейковые методы `SOMEHOW_*`. Теперь можно преобразовать эти фейковые методы в интерфейс адаптера.

| Поддельная сигнатура метода | Сигнатура адаптерного метода |
| --- | --- |
| SOMEHOW_GET_ATTRIBUTE(attr: string) => string | getAttr(attr: string) => string |
| SOMEHOW_SET_ATTRIBUTE(attr: string, value: string) | setAttr(attr: string, value: string) |
| SOMEHOW_ADD_CLASS(className: string) | addClass(className: string) |
| SOMEHOW_REMOVE_CLASS(className: string) | removeClass(className: string) |
| SOMEHOW_UPDATE_TOGGLE_COLOR_TEXT_CONTENT(textContent: string) | setToggleColorTextContent(textContent: string) |

Примечание: Мы больше не рекомендуем использовать `registerInteractionHandler` и `deregisterInteractionHandler` как адаптерные методы для добавления/удаления общих обработчиков событий. Обработка событий значительно различается между фреймворками (например, [React Synthetic Events](https://reactjs.org/docs/events.html)), поэтому мы рекомендуем управлять событиями на уровне компонентов.### Переработка вашего существующего кода в основной класс

Теперь, когда наш API адаптера определен, наш существующий код может быть переработан в основной класс.
Как правило, в нашем коде, мы определяем статический геттер `defaultAdapter`, который возвращает
адаптер сNOP сигнатурами для каждого метода. Это помогает нам проверять форму адаптера,
предотвращать ошибки адаптеров, когда методы забываются, и в будущем (и это должно быть сделано)
использовать для построения инструментов для проверки правильной формы адаптера. Этот пример показывает это,
а также использует наш класс `MDCFoundation`, который является базовым классом, от которого наследуются все основные классы.

```ts
class RedblueToggleFoundation extends MDCFoundation {
  static get defaultAdapter() {
    return {
      getAttr: (attr: string) => '',
      setAttr: (attr: string, value: string) => undefined,
      addClass: (className: string) => undefined,
      removeClass: (className: string) => undefined,
      setToggleColorTextContent: (textContent: string) => undefined,
      registerInteractionHandler: (type: string, handler: EventListener) => undefined,
      deregisterInteractionHandler: (type: string, handler: EventListener) => undefined,
    };
  }

  private toggled = false;

  constructor(adapter) {
    super({...RedblueToggleFoundation.defaultAdapter, ...adapter});
  }

  handleClick() {
    this.toggle();
  }

  isToggled() {
    return this.adapter.getAttr('aria-pressed') === 'true';
  }

  private toggle(isToggled = undefined) {
    const wasToggledExplicitlySet = isToggled === Boolean(isToggled);
    this.toggled = wasToggledExplicitlySet ? isToggled : !this.toggled;

    let toggleColor;
  }
``````markdown
Обратите внимание на использование `isToggled()` и `toggle()` вместо сеттеров и геттеров. Учитывая, что основа представляет собой более низкоуровневый API, мы считаем, что данная конвенция уместна.
this.adapter.setAttr('aria-pressed', String(this.toggled));
if (this.toggled) {
  toggleColor = 'Красный';
  this.adapter.addClass('redblue-toggle--toggled');
} else {
  toggleColor = 'Синий';
  this.adapter.removeClass('redblue-toggle--toggled');
}
this.adapter.setToggleColorTextContent(toggleColor);
}
```### Создайте компонент на основе этой основы, предоставив адаптер

Последний шаг заключается в создании вашего реального компонента с использованием основы выше. Компонент выполняет две основные задачи:

* Предоставление идиоматического интерфейса к функциональности основы в контексте хостовой среды
* Предоставление адаптера к основе, который позволит ей работать в контексте хостовой среды

Так как этот компонент является простым компонентом, он должен быть спроектирован в соответствии с простым API DOM, которое предпочитает использование геттеров и сеттеров для реализации своей функциональности (например, `checked`, `disabled` и т.д.). Наш адаптер крайне прост, так как мы можем просто переиспользовать методы, с которых начали.

```ts
class RedblueToggle extends MDCComponent {
  initialize() {
    this.listen('click', this.foundation.handleClick);
  }

  destroy() {
    this.unlisten('click', this.foundation.handleClick);
  }

  get toggled() {
    return this.foundation.isToggled();
  }

  set toggled(toggled) {
    this.foundation.toggle(toggled);
  }

  getDefaultFoundation() {
    return new RedblueToggleFoundation({
      getAttr: attr => this.root.getAttribute(attr),
      setAttr: (attr, value) => this.root.setAttribute(attr, value),
      addClass: className => this.root.classList.add(className),
      removeClass: className => this.root.classList.remove(className),
      setToggleColorTextContent: textContent => {
        this.root.querySelector<HTMLElement>('.redblue-toggle__color').textContent = textContent;
      },
    });
  }
}

Вы можете просмотреть готовый пример на CodePen.## Что делает хороший компонент

Эти дополнительные руководства предоставляют своего рода "список проверок" при создании ваших собственных компонентов. Мы строго придерживаемся их в нашем коде, и соблюдение этих правил обеспечит приятный опыт для пользователей ваших компонентов.

Полностью протестированный код

ECMAScript, по своей природе, является динамическим и гибким языком. Преимущества этой динамики и гибкости приходят за счет необходимости проверки правильности вашего кода. Единственный способ убедиться, что ваш код будет работать так, как вы ожидаете, — это выполнить этот код и убедиться, что результаты соответствуют вашим ожиданиям. Стремитесь к 100% покрытию тестами для ваших основ, адаптеров и компонентов.

Тщательно документированный и строго версионированный интерфейс адаптера

Так как авторы фреймворков будут проектировать код вокруг вашего интерфейса адаптера, важно предоставить всю необходимую информацию для их работы. Наш рекомендованный подход — документировать интерфейс адаптера в README компонента, предоставляя как сигнатуру метода, так и ожидаемое поведение метода.Также важно строго версионировать интерфейсы ваших адаптеров. Изменения в интерфейсе адаптера — даже ассоциативные — могут потенциально сломать существующие реализации или ввести реализаторов в заблуждение, заставляя их думать, что их код работает правильно, тогда как они могут упускать ключевые аспекты компонента из-за того, что не реализовали новый метод адаптера. Мы считаем, что каждое изменение в интерфейсе адаптера является разрывом, и рекомендуем этот подход.### Доступность

Мы требуем, чтобы все наши основные компоненты были полностью доступны. Мы реализуем спецификации ARIA, когда это имеет смысл, и гарантируем, что мы используем семантику, насколько это возможно, в поведении наших компонентов. Инструменты разработчика для доступности — отличный способ проанализировать, насколько доступен ваш компонент.

Сознание RTL

Компоненты должны быть RTL-осведомленными. То есть, должен быть какой-то способ, которым компонент использует стратегию для обнаружения, находится ли он в контексте RTL, и делает соответствующие корректировки. Мы используем нашу библиотеку @material/rtl для помощи в этом.

Поддержка тем

Компонент должен быть способен изменяться в соответствии с темой. Тема может быть определена любым способом, которым вы хотите. Это может быть с помощью основных и второстепенных цветов, или вы можете выбрать, чтобы выставить scss переменные или CSS Custom properties, специфичные для вашего компонента. Независимо от выбранного способа, убедитесь, что клиенты могут легко изменять общие эстетические элементы вашего компонента, чтобы он соответствовал их общему дизайну. Мы используем @material/theme для этой цели.## Общие наилучшие практики

Даже когда компонент удовлетворяет всем вышеупомянутым требованиям, он все еще может столкнуться с проблемами. Следуйте рекомендациям ниже, чтобы избежать проблем и непреднамеренных ситуаций насколько это возможно.> Также, как и с любым набором лучших практик, важно помнить, что эти являются руководствами, а не жесткими и неизменными правилами. Если какая-то лучшая практика мешает вам улучшать или поддерживать ваш компонент, игнорируйте её. Однако, обосновывайте своё решение, предпочтительно в виде документации или комментария кода.

Делайте то, что ожидает пользователь

Это наша "золотая" рекомендация, если можно так сказать. Проектируйте API ваших компонентов так, чтобы они были интуитивно понятными и простыми для понимания. Убедитесь, что ваши компоненты ведут себя так, как пользователь мог бы предсказать. Например, геттер checked для MDCCheckbox возвращает булево значение, указывающее, находится ли внутреннее состояние чекбокса в состоянии "выбран". Он не создаёт побочных эффектов и работает точно так же, как HTMLInputElement.prototype.checked, когда его type установлен на "checkbox". При проектировании ваших компонентов моделируйте их в соответствии с окружением, в котором вы ожидаете, что пользователи будут использовать их. В нашем случае, наши простые компоненты моделируются в соответствии с API DOM.### Проектируйте интерфейсы адаптеров так, чтобы они были простыми и интуитивно понятными

Это следует за вышеупомянутой практикой выполнения того, что ожидает пользователь. Поскольку потребители библиотеки будут реализовывать методы адаптера, они должны быть простыми для реализации, а также прямолинейными и интуитивно понятными. Большинство методов адаптера должны быть однострочными, такими как "добавить класс" или "обновить свойство стиля". Пользователи не должны гадать о цели метода адаптера, а также о том, что должны быть его входные и выходные данные.

Например, хороший метод интерфейса адаптера может выглядеть так:

Подпись метода Описание
setStyle(styleProperty: string, value: string) => void Устанавливает стиль на корневом элементе, принимая styleProperty и значение для этого свойства.

В отличие от плохого интерфейса адаптера, такого как тот, что ниже:

Подпись метода Описание
applyComponentStyles() => void Устанавливает правильные стили на корневом элементе компонента. Посмотрите нашу документацию для получения дополнительной информации.

Вышеупомянутый интерфейс адаптера больше подходит для метода основания. Единственной обязанностью адаптера должно быть выполнение обновлений стилей, а не определение того, какие они.### Не ссылайтесь на объекты-хосты внутри кода основания

Чтобы ваша основа была совместима с максимальным количеством фреймворков, избегайте прямого ссылания на объекты хоста внутри них. Это включает window, document, console и другие. Используйте только глобальные объекты, определенные в спецификации ECMAScript, в вашей основе.

Мы делаем исключение для этого правила для requestAnimationFrame, но в будущем мы можем переработать и это. Кроме того, обходным путем для работы с объектами хоста в основе является запрос их через адаптер.

Очистка всех ссылок при разрушении

Это включает обработчики событий, идентификаторы таймеров, идентификаторы кадров анимации и любые другие внешние ссылки, которые могут быть сохранены. Существует два точных критерия для проверки того, что это делается:

  1. init() (или initialize() в простом компоненте) и destroy() являются рефлексивными. Например, любые обработчики событий, прикрепленные в init(), удаляются в destroy().
  2. Каждый вызов, который создает внешнюю ссылку (например, setTimeout(), requestAnimationFrame()), отслеживается, и очищается в destroy(). Например, каждый вызов setTimeout() должен сохранять свой идентификатор в компоненте/основе, и вызывать clearTimeout() на нем в destroy().

Создание компонентов для MDC WebСледующие руководства предназначены для тех, кто хочет внести прямой вклад в MDC Web. В дополнение к соблюдению всех вышеупомянутых практик, у нас есть дополнительные соглашения, которые мы ожидаем, что вкладчики будут соблюдать. Стоит отметить, что большинство этих соглашений, включая наш стиль кодирования, формат сообщений коммитов и охват тестов, автоматически соблюдаются с помощью линтеров, чтобы вкладчики могли быстро и уверенно работать, а члены основной команды не тратили время и энергию на придирки к пулл-запросам.### Структура файлов

  • Исходные файлы: Располагаются под packages/.
  • Файлы тестов: Располагаются под packages/<mdc-component>/test/.

Типичный компонент в нашей базе кода выглядит следующим образом:

packages/
  ├── mdc-component/
      ├── test/
          ├── foundation.test.ts # Единичные тесты для основы компонента
          ├── mdc-component.test.ts # Единичные тесты для компонента
      ├── README.md # Инструкции по использованию и документация API
      ├── adapter.ts # Интерфейс адаптера, реализуемый обёртками фреймворков и чистым компонентом
      ├── foundation.ts # Бизнес-логика, независимая от фреймворка, используемая обёртками фреймворков и чистым компонентом
      ├── component.ts # Чистый компонент и реализации адаптера для клиентов, не использующих фреймворк
      ├── constants.ts # Константные значения, используемые одним или несколькими файлами в пакете (например, cssClasses, strings, numbers)
      ├── index.ts # Перенаправляет экспорт из других файлов в пакете (adapter, foundation, component, util и т.д.)
      ├── types.ts # (необязательно) Содержит типы и интерфейсы, выведенные в публичные API, не связанные с чистым компонентом
      ├── util.ts # (необязательно) Помощники, независимые от фреймворка (например, обнаружение функций)
      ├── mdc-component.scss # Основной файл исходного кода CSS для компонента
      └── package.json # Файл пакета компонента

**Каждый компонент должен иметь эти файлы перед тем, как мы примем PR для них.**При внесении нового компонента мы рекомендуем вам посмотреть на существующие компоненты, чтобы лучше понять наши конвенции. Ваш новый компонент должен "вписываться" в существующие компоненты.

Кроме того, все новые компоненты требуют следующего в их package.json:

"publishConfig": {
  "access": "public"
}

Это необходимо для того, чтобы lerna мог автоматически публиковать новые скопированные пакеты.

Мы также требуем список ключевых слов для каждого пакета. Этот список должен всегда включать material components и material design, за которыми следуют имя компонента:

"keywords": [
  "material components",
  "material design",
  <COMPONENT_NAME>
]

Например, если вы создаете компонент чекбокса, keywords должны включать material components, material design и checkbox.

Ниже приведен пример полного package.json для нового компонента:

{
  "name": "@material/example",
  "version": "0.0.0",
  "description": "Компонент Material Components для веба example",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/material-components/material-components-web.git"
  },
  "keywords": [
    "material components",
    "material design",
    "example"
  ],
  "publishConfig": {
    "access": "public"
  }
}

Строки лицензии

Нам необходимо размещать следующее в начале каждого исходного кодового файла, включая тесты, демонстрации и html-демонстрации. Строки лицензии следующие:

Copyright <ГОД> Google Inc.
```Данное разрешение предоставляется бесплатно любому лицу, получившему копию
этого программного обеспечения и связанных с ним документационных файлов («Программное обеспечение»), для использования
Программного обеспечения без каких-либо ограничений, включая, но не ограничиваясь правами
на использование, копирование, изменение, объединение, публикацию, распространение, предоставление sublicenses и/или продажу
копий Программного обеспечения, а также для предоставления лицам, которым предоставляется Программное обеспечение, права на то, чтобы
делать то же самое, при условии соблюдения следующих условий:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ПОДКЛЮЧЕНИЕ ПОДКЛЮЧЕНО "КАК ЕСТЬ", БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЯ, ГАРАНТИЯМИ ТОРГОВЛЕНИЯ, ПРИГОДНОСТИ ДЛЯ КОНКРЕТНЫХ ЦЕЛЕЙ И НЕНАРУШЕНИЯ. В НИКАКОМ СЛУЧАЕ АВТОРЫ И ДОЛЖНИКИ ПРАВА КОПИРОВАНИЯ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ЗА КАКИЕ-ЛИБО ПРЕТЕНЗИИ, УЩЕРБЫ ИЛИ ДРУГИЕ ОТВЕТСТВЕННОСТИ, В ТОМ ЧИСЛЕ В СВЯЗИ С ДЕЙСТВИЕМ ДОГОВОРА, ДЕЛИКТОМ ИЛИ ИНЫМ, ВОЗНИКШИМ ИЗ, В СВЯЗИ С ИЛИ В СВЯЗИ С ПОДКЛЮЧЕНИЕМ ПОДКЛЮЧЕНИЯ ИЛИ ИСПОЛЬЗОВАНИЕМ ИЛИ ДРУГИМИ СВЯЗЯМИ С ПОДКЛЮЧЕНИЕМ ПОДКЛЮЧЕНИЯ.

```Пожалуйста, добавьте этот комментарий в начало каждого исходного файла, заменив `<YEAR>` на год создания файла.

### SCSS

#### Отдельно выделяйте переиспользуемые переменные и миксины из основного SCSS

Если переменные и миксины предназначены для использования вне одного стилейшета, перенесите их
в [частичные файлы SASS](http://sass-lang.com/guide#topic-4). Эти файлы затем могут быть включены
в другие стилейшеты без повторного опускания лишнего CSS. В качестве правила, никогда не `@import`
файлы SASS, которые выводят CSS, так как это, скорее всего, будет дублированным выводом.

#### Следуйте модифицированному паттерну BEM

Мы следуем модифицированному варианту [паттерна BEM](http://getbem.com/), который определен в наших
[правилах stylelint](../.stylelintrc.yaml#L252-L255). Это, в основном:```scss
.mdc-block {

}

.mdc-block__element {

}

.mdc-block--modifier {

}

Обычно, мы структурируем это в нашем коде следующим образом:

.mdc-block {
  // ...

  &__element {
    // ...
  }
}

.mdc-block--modifier {
  // ...

  .mdc-block__element {
    // ...
  }
}

Иногда вам потребуется квалифицировать селекторы, такие как .some-context .mdc-block {/* ... */}. Stylelint будет жаловаться на это, что можно отключить, вставив следующее:

// stylelint-disable plugin/selector-bem-pattern

// стили, которые вызывают жалобы по селекторам BEM...

// stylelint-enable plugin/selector-bem-pattern

Используйте mdc-theme для темизации

Все тематические элементы компонента должны быть указаны через mdc-theme. Это обеспечит, что компонент интегрируется гармонично в нашу систему темизации.

Используйте mdc-rtl для поддержки RTL

Все RTL-обработки внутри стилей компонента должны быть указаны через mdc-rtl. Это обеспечит, что все компоненты обрабатывают RTL-контексты одинаковым образом и будут вести себя консистентно.

Javascript

Определите статический метод attachTo(root) для каждого компонента

Все компоненты должны определить статический метод attachTo с следующим сигнатурой:

static attachTo(element: HTMLElement) => Constructor

например:

class MDCNewComponent extends MDCComponent {
  static attachTo(root) {
    return new MDCNewComponent(root);
  }
}
````mdc-auto-init` требует присутствия этого метода, и мы гарантируем его предоставление для удобства наших пользователей. Мы говорили о написании правила для линтера для этого в будущем.

#### Определите getter для defaultAdapter для каждого фундамента
Все фундаменты **должны** определить статический метод `defaultAdapter`, который возвращает адаптер со всеми определёнными функциями. Функции должны быть, по сути, NOPs; принимать никаких параметров и возвращать правильный тип (например, `false` для булева типа, `0` для числа, `{}` для объекта и т.д.). Наша конвенция состоит в том, чтобы аннотировать функцию с помощью встроенных комментариев с использованием [типовых аннотаций TypeScript](https://basarat.gitbooks.io/typescript/content/docs/types/type-system.html).Также принято переопределять конструктор фундамента для смешивания переданного параметра `adapter` с объектом по умолчанию. Это гарантирует, что адаптер имеет правильную форму.

```js
class MDCNewComponentFoundation extends MDCFoundation {
  static get defaultAdapter() {
    return {
      addClass: (/* className: string */) => {},
      getAttr: (/* attr: string */) => /* string */ '',
      // ...
    }
  }

  constructor(adapter) {
    super(...MDCNewComponentFoundation.defaultAdapter, ...adapter);
  }
}

Конечно, это приходит за счёт потенциального затенения ошибочных переданных адаптеров. Однако, мы планируем предоставить типовые определения для адаптеров в будущем, чтобы помочь смягчить это. Подобно упомянутому выше правилу, мы также хотели бы предоставить правила для проверки этих конвенций.

Определите все экспортированные CSS-классы, строк и чисел как константы фундамента.

  • Все CSS-классы, ссылающиеся на фундамент компонента, должны быть ссылающимися через статический getter cssClasses.
  • Все строки, используемые вне контекста класса фундамента (CSS-селекторы, имена пользовательских событий, текст, который потенциально может быть локализован и т.д.), должны быть ссылающимися через статический getter strings.
  • Все семантические числа, используемые фундаментом (длины таймаута, длительности трансформации и т.д.), должны быть ссылающимися через статический getter numbers.
  • Эти константы должны быть определены в файле constants.ts, а затем проксироваться через фундамент.```ts // constants.ts

export const cssClasses = { ROOT: 'mdc-new-component', ACTIVE: 'mdc-new-component--active', DISABLED: 'mdc-new-component--disabled', };

export const strings = { CHILD_SELECTOR: '.mdc-new-component__child', CUSTOM_EVENT: 'MDCNewComponent:event', };

```javascript
export const numbers = {
  DEFAULT_THROTTLE_DELAY_MS: 300,
};
```

// foundation.ts

```javascript
import {cssClasses, strings, numbers} from './constants';

class MDCNewComponentFoundation extends MDCFoundation {
  static get defaultAdapter() {
    // ...
  }

  static get cssClasses() {
    return cssClasses;
  }

  static get strings() {
    return strings;
  }

  static get numbers() {
    return numbers;
  }
}
```

Основная цель этого — чтобы наши компоненты могли взаимодействовать с аспектами инфраструктуры фронтенда Google, такими как механизм [переименования CSS-классов](https://github.com/google/closure-stylesheets#renaming) в Closure Stylesheets. Кроме того, это обеспечивает дополнительную выгоду в виде семантического кода и меньшего количества магических строк и чисел.

#### Расширение компонентов и оснований от классов mdc-base.
Чтобы гарантировать последовательное поведение всех пакетов, все компоненты должны наследоваться от `MDCComponent`, а все основания — от `MDCFoundation`. Дополнительная информация о обоих этих классах доступна в [README mdc-base](../packages/mdc-base).

#### Пакеты должны быть зарегистрированы с нашей системой сборки и с пакетом material-components-web
Каждый раз, когда вы создаете новый компонент, важно уведомить соответствующие инструменты и пакеты о нем. Конкретно:
```- Убедитесь, что для него существует запись в `webpack.config.js` для модулей `js-components` и `css`.
- Убедитесь, что он добавлен как зависимость `material-components-web`. Если компонент содержит стили, убедитесь, что они импортированы с помощью `@import` в `material-components-web.scss`. Если компонент содержит JavaScript, убедитесь, что его пространство имен компонента экспортировано в `material-components-web`, и что он зарегистрирован с `mdc-auto-init`. Наконец, не забудьте добавить его в `package.json` пакета `material-components-web`.
- Убедитесь, что правильный **предмет коммита** для пакета добавлен в массив `config.validate-commit-msg.scope.allowed` в `package.json` на верхнем уровне репозитория. Предмет коммита — это _имя компонента без префикса `mdc-`/`@material/`_. Например, для `mdc-icon-button` правильный предмет — `icon-button`.#### Совместимость с TypeScript
```Все основные компоненты MDC Web должны быть полностью совместимы с режимом строгого соответствия [TypeScript](https://www.typescriptlang.org/). Мы предоставили список требований и дальнейшее объяснение соответствия TypeScript, а также конвенции, примеры и распространенные паттерны TypeScript, с которыми вы можете не быть знакомы, в нашем [Руководстве по лучшим практикам программирования](./code/best_practices.md).```

### Проверка

Следующие руководства следует использовать для написания тестов для кода MDC Web. Наши тесты написаны с использованием [Jasmine](https://jasmine.github.io/) и запускаются с помощью [Karma](https://karma-runner.github.io/1.0/index.html).

#### Проверка адаптеров основ
При тестировании основ, убедитесь, что хотя бы один из ваших тестовых случаев использует метод `verifyDefaultAdapter`, определенный с помощью наших [помощников для основ](../testing/helpers/foundation.ts). Это делается для того, чтобы убедиться, что интерфейсы адаптеров не изменяются непреднамеренно.

#### Использование вспомогательных методов
У нас есть модули-помощники в [testing/helpers](../testing/helpers) для таких вещей, как запуск тестов для основ, перехват методов адаптеров для прослушивания событий и работа с `requestAnimationFrame`. Мы рекомендуем использовать их в вашем коде для того, чтобы сделать написание тестов как можно более простым!#### Использование `getFixture` для фикстур DOM
Чтобы создать фикстуры для тестов компонентов/адаптеров, используйте вспомогательный метод [#getFixture](../testing/dom/index.ts).

#### Всегда очищайте DOM после каждого теста
Это важно. _Перед завершением теста убедитесь, что все элементы, прикрепленные к DOM, были удалены_.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/mirrors-material-components-web.git
git@api.gitlife.ru:oschina-mirror/mirrors-material-components-web.git
oschina-mirror
mirrors-material-components-web
mirrors-material-components-web
master