griffincss-ui 0.23.0 → 0.24.0-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,8 @@
7
7
  // Правил на .gr-modal здесь нет: класс принадлежит пакету ui, лайтбокс
8
8
  // только уточняет его своим классом.
9
9
 
10
+ @use '../mixins' as m;
11
+
10
12
  .gr-lightbox {
11
13
  inline-size: 100%;
12
14
  block-size: 100%;
@@ -81,6 +83,14 @@
81
83
  transition: background-color var(--gr-transition);
82
84
  }
83
85
 
86
+ // Закрытие — полосками: знак «×» в 1,5rem садится на 2 px ниже центра
87
+ // круга во всех движках.
88
+ .gr-lightbox-close {
89
+ @include m.gr-cross(1rem);
90
+
91
+ --gr-cross-color: hsl(var(--gr-hsl-white));
92
+ }
93
+
84
94
  .gr-lightbox-close:hover,
85
95
  .gr-lightbox-prev:hover,
86
96
  .gr-lightbox-next:hover {
@@ -3,6 +3,8 @@
3
3
  // Без скрипта его нет: сколько файлов выбрано, показывает само поле,
4
4
  // а оформление поля — модуль .gr-file пакета ui.
5
5
 
6
+ @use '../../mixins' as m;
7
+
6
8
  .gr-file-list {
7
9
  display: flex;
8
10
  flex-direction: column;
@@ -45,10 +47,13 @@
45
47
  }
46
48
 
47
49
  .gr-file-remove {
50
+ @include m.gr-cross(0.75rem);
51
+
52
+ --gr-cross-color: var(--gr-color-text-secondary);
53
+
54
+ position: relative;
48
55
  display: inline-flex;
49
56
  flex: 0 0 auto;
50
- align-items: center;
51
- justify-content: center;
52
57
  inline-size: 1.75rem;
53
58
  block-size: 1.75rem;
54
59
  margin: 0;
@@ -56,17 +61,14 @@
56
61
  border: 0;
57
62
  border-radius: var(--gr-radius);
58
63
  background: none;
59
- color: var(--gr-color-text-secondary);
60
- font: inherit;
61
- font-size: 1.125rem;
62
- line-height: 1;
63
64
  cursor: pointer;
64
65
  }
65
66
 
66
67
  @media (hover: hover) {
67
68
  .gr-file-remove:hover {
69
+ --gr-cross-color: var(--gr-color-danger);
70
+
68
71
  background-color: var(--gr-color-surface-raised);
69
- color: var(--gr-color-danger);
70
72
  }
71
73
  }
72
74
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Griffincss UI — Runtime v0.23.0
2
+ * Griffincss UI — Runtime v0.24.0-dev
3
3
  * Опциональный рантайм пакета компонентов. Делает ровно то, чего платформа
4
4
  * не даёт вовсе; всё, что умеют <details>, <dialog> и Popover API, остаётся
5
5
  * за ними. Без этого файла компоненты работают — просто без перечисленного.
@@ -50,7 +50,7 @@
50
50
  })(function () {
51
51
  'use strict';
52
52
 
53
- var VERSION = '0.23.0';
53
+ var VERSION = '0.24.0-dev';
54
54
 
55
55
  var OVERLAY_ATTR = 'data-gr-overlay-close';
56
56
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * GriffinJS — Core v0.23.0
2
+ * GriffinJS — Core v0.24.0-dev
3
3
  * Опциональный слой виджетов с состоянием поверх Griffincss: слайдер,
4
4
  * галерея, лайтбокс, параллакс, мегаменю. Подключается одной строкой
5
5
  * и одним файлом; страница без него — законное и рабочее состояние.
@@ -38,7 +38,7 @@
38
38
  })(function () {
39
39
  'use strict';
40
40
 
41
- var VERSION = '0.23.0';
41
+ var VERSION = '0.24.0-dev';
42
42
 
43
43
  // Реестры. Модуль зовёт defineEngine/defineWidget; ядро — единственное
44
44
  // место, которое знает, как их применить.
@@ -19,9 +19,19 @@
19
19
  * fill — знак свободного слота в ней, «_» по умолчанию.
20
20
  *
21
21
  * База без скрипта: pattern и inputmode на элементе — платформа проверяет
22
- * сама, скрипт лишь помогает вводить и ни pattern, ни проверку не трогает.
23
- * Из маски он берёт только два удобства: подсказку и inputmode="numeric"
24
- * для маски из одних цифр — и то, если автор не задал своих.
22
+ * сама. Авторский pattern маска не трогает и не заменяет; из маски она берёт
23
+ * два удобства подсказку и inputmode="numeric" для маски из одних цифр,
24
+ * и то, если автор не задал своих.
25
+ *
26
+ * Недобор. Непустое значение с незаполненными обязательными слотами — своя
27
+ * ошибка проверки: setCustomValidity(incomplete) ставится сразу, поэтому
28
+ * checkValidity() даёт false и форма не уходит с половиной номера. На полном
29
+ * значении custom-error пуст, и единственным судьёй снова становится pattern.
30
+ * Пустое поле маска не трогает: пустое — это required платформы, и поле
31
+ * без required обязательным не становится. Красным (aria-invalid) поле
32
+ * помечается ТОЛЬКО по уходу фокуса и светлеет, как только значение стало
33
+ * полным: ругаться на человека, пока он печатает, — не проверка. Там, где
34
+ * недобор законен, выход не требует нового API — токен ? в формате.
25
35
  *
26
36
  * Каретка. Правки перехватываются в beforeinput: новое значение считается
27
37
  * здесь, пишется целиком, и каретка встаёт за только что введённый знак —
@@ -31,16 +41,17 @@
31
41
  * браузер делает своё, а маска потом приводит значение к формату по input
32
42
  * или compositionend. Это единственный случай, когда каретка уходит в конец.
33
43
  *
34
- * Маска пишет value контрола — первый такой виджет в слое. Расширение
35
- * инварианта 7 объявлено в docs/griffinjs-architecture.html («Инварианты»)
36
- * и в правилах правки слоя. После каждой своей записи она шлёт input
44
+ * Маска пишет value контрола и его валидность — первый такой виджет в слое.
45
+ * Расширение инварианта 7 объявлено в docs/griffinjs-architecture.html
46
+ * («Инварианты») и в правилах правки слоя: пишешь value пиши и валидность,
47
+ * и возвращай её в destroy(). После каждой своей записи она шлёт input
37
48
  * (а по уходу фокуса — change), поэтому фреймворк узнаёт о значении
38
49
  * так же, как о набранном руками.
39
50
  */
40
51
  (function (G) {
41
52
  'use strict';
42
53
 
43
- var DEFAULTS = { format: '', hint: true, fill: '_' };
54
+ var DEFAULTS = { format: '', hint: true, fill: '_', incomplete: 'Значение набрано не полностью' };
44
55
 
45
56
  // Что принимает слот. Буква — любая по Юникоду: маска номерного знака
46
57
  // на кириллице не хуже латинской.
@@ -157,6 +168,7 @@
157
168
  var tokens;
158
169
  var last = null; // последнее записанное значение
159
170
  var focused = null; // значение на момент фокуса — для change
171
+ var short = false; // набрано, но не до конца
160
172
  var ownHint = o.hint && !el.getAttribute('placeholder');
161
173
  var ownMode = !el.getAttribute('inputmode');
162
174
 
@@ -170,6 +182,12 @@
170
182
 
171
183
  attrs.set(el, 'data-gr-state', !result.raw ? 'empty' : result.complete ? 'complete' : 'partial');
172
184
 
185
+ // Недобор — своя ошибка; пустое поле остаётся заботой required.
186
+ short = !!result.raw && !result.complete;
187
+
188
+ if (typeof el.setCustomValidity === 'function') el.setCustomValidity(short ? o.incomplete : '');
189
+ if (!short) attrs.set(el, 'aria-invalid', null);
190
+
173
191
  if (k !== undefined && typeof el.setSelectionRange === 'function') {
174
192
  var at = caret(result, k);
175
193
 
@@ -264,6 +282,7 @@
264
282
  // правку он не видел. Событие шлётся здесь по тому же правилу —
265
283
  // значение по уходу фокуса отличается от значения на входе.
266
284
  function onBlur() {
285
+ if (short) attrs.set(el, 'aria-invalid', 'true');
267
286
  if (focused !== null && el.value !== focused) fire(el, 'change');
268
287
  focused = null;
269
288
  }
@@ -298,6 +317,8 @@
298
317
  destroy: function () {
299
318
  events.removeAll();
300
319
  attrs.restore();
320
+
321
+ if (typeof el.setCustomValidity === 'function') el.setCustomValidity('');
301
322
  }
302
323
  };
303
324
  });
@@ -15,8 +15,10 @@
15
15
  * зовётся иначе, чем виджет: data-gr-mask на позиции списка ядро приняло бы
16
16
  * за виджет и попыталось бы надеть маску на <option>. Пустой <select> заполняется
17
17
  * из таблицы griffinjs-countries.js, если она подключена; без неё виджет
18
- * предупреждает и работает как поле без маски. Данные со своим темпом
19
- * обновления библиотека вместе с кодом не сопровождает.
18
+ * предупреждает и работает как поле без маски. Начальная страна списка
19
+ * из таблицы параметр country; без него первой стоит первая по алфавиту
20
+ * языка страницы, и виджет предупреждает об этом в консоли. Данные
21
+ * со своим темпом обновления библиотека вместе с кодом не сопровождает.
20
22
  *
21
23
  * Имя страны и флаг — у платформы: Intl.DisplayNames в языке страницы
22
24
  * (lang документа) и пара региональных индикаторов из двух букв ISO.
@@ -34,6 +36,13 @@
34
36
  * два поля: код и национальный номер; целиком он в value() и в событии
35
37
  * griffin:change.
36
38
  *
39
+ * Проверка приходит от маски и вместе со страной: недобранный номер
40
+ * не проходит checkValidity(), и смена кода пересчитывает полноту —
41
+ * девяти знаков хватает Беларуси и мало России. Проверяется ДЛИНА номера
42
+ * по маске выбранной страны, а не тип номера и не диапазон оператора:
43
+ * libphonenumber в замену не входит. value() при этом отражает набранное,
44
+ * даже неполное, — полнота отдаётся признаком complete в griffin:change.
45
+ *
37
46
  * База без скрипта: type="tel" и <select> кодов в .gr-input-group —
38
47
  * обе части платформенные.
39
48
  */
@@ -129,6 +138,11 @@
129
138
  select.appendChild(option);
130
139
  created.push(option);
131
140
  }
141
+
142
+ // Без country первой стоит первая по алфавиту языка страницы —
143
+ // на русской это Австралия, +61. Угадывать страну за автора виджет
144
+ // не берётся: ошибся бы тише, чем сейчас. Но и молчать не должен.
145
+ if (!o.country) G.warn('телефон: страна не задана — выбрана первая по алфавиту; укажите country');
132
146
  }
133
147
 
134
148
  if (!options().length) {
@@ -184,7 +198,7 @@
184
198
  function emit() {
185
199
  var c = info(current());
186
200
 
187
- G.emit('griffin:change', el, { iso: c.iso, code: c.code, value: value() });
201
+ G.emit('griffin:change', el, { iso: c.iso, code: c.code, value: value(), complete: mask ? mask.complete() : true });
188
202
  }
189
203
 
190
204
  // Полный номер с плюсом: страна — по самому длинному коду, который
@@ -27,7 +27,7 @@
27
27
  * Мультивыбор (Этап 38g) — флаг multiple, а не новый виджет:
28
28
  *
29
29
  * <div class="gr-combobox" data-gr-combobox="src: /tags?q={q}; multiple">
30
- * <select name="tags[]" multiple>
30
+ * <select class="gr-select" name="tags[]" multiple>
31
31
  * <option value="css" selected>CSS</option>
32
32
  * </select>
33
33
  * <input class="gr-input" type="search">