griffincss-ui 0.26.2 → 0.27.1
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.
- package/dist/griffincss-ui-scoped.css +1 -1
- package/dist/griffincss-ui.css +1 -1
- package/dist/griffincss-ui.js +1 -1
- package/dist/griffincss-ui.js.map +1 -1
- package/dist/griffinjs-combobox.js +1 -1
- package/dist/griffinjs-combobox.js.map +1 -1
- package/dist/griffinjs-core.js +1 -1
- package/dist/griffinjs-core.js.map +1 -1
- package/dist/griffinjs-counter.js +1 -1
- package/dist/griffinjs-counter.js.map +1 -1
- package/dist/griffinjs-datetime.js +1 -1
- package/dist/griffinjs-datetime.js.map +1 -1
- package/dist/griffinjs-dialog.js +1 -1
- package/dist/griffinjs-dialog.js.map +1 -1
- package/dist/griffinjs-dropdown.js +1 -1
- package/dist/griffinjs-dropdown.js.map +1 -1
- package/dist/griffinjs-fields.js +1 -1
- package/dist/griffinjs-fields.js.map +1 -1
- package/dist/griffinjs-file.js +1 -1
- package/dist/griffinjs-file.js.map +1 -1
- package/dist/griffinjs-lightbox.js +1 -1
- package/dist/griffinjs-lightbox.js.map +1 -1
- package/dist/griffinjs-loader.js +1 -1
- package/dist/griffinjs-loader.js.map +1 -1
- package/dist/griffinjs-mask.js +1 -1
- package/dist/griffinjs-mask.js.map +1 -1
- package/dist/griffinjs-megamenu.js +1 -1
- package/dist/griffinjs-megamenu.js.map +1 -1
- package/dist/griffinjs-otp.js +1 -1
- package/dist/griffinjs-otp.js.map +1 -1
- package/dist/griffinjs-phone.js +1 -1
- package/dist/griffinjs-phone.js.map +1 -1
- package/dist/griffinjs-range.js +1 -1
- package/dist/griffinjs-range.js.map +1 -1
- package/dist/griffinjs-rating.js +1 -1
- package/dist/griffinjs-rating.js.map +1 -1
- package/dist/griffinjs-slider.js +1 -1
- package/dist/griffinjs-slider.js.map +1 -1
- package/dist/griffinjs-sortable.js +1 -1
- package/dist/griffinjs-sortable.js.map +1 -1
- package/dist/griffinjs-tooltip.js +1 -1
- package/dist/griffinjs-tooltip.js.map +1 -1
- package/dist/griffinjs-track.js +1 -1
- package/dist/griffinjs-track.js.map +1 -1
- package/dist/griffinjs-validate.js +1 -1
- package/dist/griffinjs-validate.js.map +1 -1
- package/dist/griffinjs.css +1 -1
- package/dist/griffinjs.js +1 -1
- package/dist/griffinjs.js.map +1 -1
- package/package.json +2 -2
- package/scss/_prose.scss +116 -0
- package/scss/_steps.scss +81 -38
- package/scss/_table.scss +17 -6
- package/scss/griffincss-ui-scoped.scss +1 -0
- package/scss/griffincss-ui.scss +1 -0
- package/scss/griffinjs/_track.scss +10 -0
- package/scss/griffinjs/griffinjs.scss +1 -1
- package/src/griffincss-ui.js +5 -5
- package/src/griffinjs/core/griffinjs-core.js +10 -10
- package/src/griffinjs/core/loader.js +2 -2
- package/src/griffinjs/core/options.js +1 -1
- package/src/griffinjs/core/track.js +2 -2
- package/src/griffinjs/fields/counter.js +1 -1
- package/src/griffinjs/fields/datetime.js +2 -2
- package/src/griffinjs/fields/file.js +1 -1
- package/src/griffinjs/fields/mask.js +1 -1
- package/src/griffinjs/fields/otp.js +1 -1
- package/src/griffinjs/fields/phone.js +3 -3
- package/src/griffinjs/fields/rating.js +1 -1
- package/src/griffinjs/fields/validate.js +1 -1
- package/src/griffinjs/widgets/combobox.js +19 -6
- package/src/griffinjs/widgets/dialog.js +41 -12
- package/src/griffinjs/widgets/dropdown.js +1 -1
- package/src/griffinjs/widgets/gallery.js +1 -1
- package/src/griffinjs/widgets/lightbox.js +67 -20
- package/src/griffinjs/widgets/megamenu.js +28 -8
- package/src/griffinjs/widgets/range.js +2 -2
- package/src/griffinjs/widgets/slider.js +1 -1
- package/src/griffinjs/widgets/sortable.js +1 -1
- package/src/griffinjs/widgets/tooltip.js +1 -1
package/scss/_steps.scss
CHANGED
|
@@ -18,12 +18,17 @@
|
|
|
18
18
|
// Состояний три: пройденный (.gr-step-done), текущий (aria-current="step")
|
|
19
19
|
// и ожидающий — он же состояние по умолчанию. Текущий находится по тому же
|
|
20
20
|
// признаку, по которому его находит программа чтения с экрана; класса
|
|
21
|
-
// для него нет намеренно.
|
|
21
|
+
// для него нет намеренно. Перечню этапов без хода — «Этапы работы»
|
|
22
|
+
// лендинга — состояния не нужны: .gr-steps-plain делает все шаги
|
|
23
|
+
// равноправными.
|
|
22
24
|
//
|
|
23
25
|
// Знак в маркере кладут в разметку: галочка у пройденного шага и номер
|
|
24
26
|
// у остальных — это содержимое, а не оформление. Цвет остаётся вторым
|
|
25
27
|
// признаком поверх знака и позиции, а не единственным.
|
|
26
28
|
|
|
29
|
+
@use 'griffincss-core/scss/breakpoints' as bp;
|
|
30
|
+
@use 'griffincss-core/scss/container-mixins' as cq;
|
|
31
|
+
|
|
27
32
|
.gr-steps {
|
|
28
33
|
--gr-step-marker-size: 2rem;
|
|
29
34
|
|
|
@@ -125,6 +130,26 @@
|
|
|
125
130
|
line-height: 1.35;
|
|
126
131
|
}
|
|
127
132
|
|
|
133
|
+
// Подпись и пояснение одним блоком: в колонке он встаёт справа от маркера,
|
|
134
|
+
// в ряду — под ним, и там ведёт себя как её отсутствие: строки друг под
|
|
135
|
+
// другом с тем же зазором, что у шага. Нужен разметке, которая бывает
|
|
136
|
+
// и тем и другим (.gr-steps-stack-*).
|
|
137
|
+
.gr-step-body {
|
|
138
|
+
display: flex;
|
|
139
|
+
flex-direction: column;
|
|
140
|
+
gap: calc(var(--gr-ui-gap) * 0.5);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// --- Равноправный список ----------------------------------------------------
|
|
144
|
+
|
|
145
|
+
// Перечень этапов без хода процесса: подпись цвета текста, маркер
|
|
146
|
+
// акцентный, линия нейтральная. Вес — как у .gr-step, и стоит до состояний:
|
|
147
|
+
// пройденный и текущий шаг в таком списке по-прежнему сильнее.
|
|
148
|
+
:where(.gr-steps-plain) .gr-step {
|
|
149
|
+
--gr-step-color: var(--gr-color-text);
|
|
150
|
+
--gr-step-marker-fg: var(--gr-color-accent);
|
|
151
|
+
}
|
|
152
|
+
|
|
128
153
|
// --- Состояния --------------------------------------------------------------
|
|
129
154
|
|
|
130
155
|
// Пройденный: его хвост залит акцентом — путь от него дальше проделан.
|
|
@@ -157,41 +182,59 @@
|
|
|
157
182
|
|
|
158
183
|
// Колонка: маркер слева, подпись справа. На узком экране это единственный
|
|
159
184
|
// работающий вариант — горизонтальный ряд из четырёх шагов там нечитаем.
|
|
160
|
-
.gr-steps-vertical
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
185
|
+
// Правила колонки описаны один раз: .gr-steps-vertical — всегда,
|
|
186
|
+
// .gr-steps-stack-{bp} и -c{bp} — ниже порога (см. ниже).
|
|
187
|
+
@mixin gr-steps-vertical($s) {
|
|
188
|
+
#{$s} {
|
|
189
|
+
flex-direction: column;
|
|
190
|
+
gap: var(--gr-gap);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#{$s} > :where(li) {
|
|
194
|
+
flex: none;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
#{$s} .gr-step {
|
|
198
|
+
flex: none;
|
|
199
|
+
flex-direction: row;
|
|
200
|
+
align-items: flex-start;
|
|
201
|
+
gap: var(--gr-ui-gap);
|
|
202
|
+
text-align: start;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// В колонке хвост идёт вниз от маркера до маркера следующего шага. Длину
|
|
206
|
+
// задают оба вылета сразу, а block-size: auto считает её из них: сколько бы
|
|
207
|
+
// текста ни висело под маркером, линия дотянется — это и есть довод
|
|
208
|
+
// в пользу хвоста, а не отрезка фиксированной длины.
|
|
209
|
+
#{$s} .gr-step::after {
|
|
210
|
+
inset-block: var(--gr-step-marker-size) calc(var(--gr-gap) * -1);
|
|
211
|
+
inset-inline: calc(var(--gr-step-marker-size) / 2) auto;
|
|
212
|
+
inline-size: var(--gr-border-width);
|
|
213
|
+
block-size: auto;
|
|
214
|
+
margin-block-start: 0;
|
|
215
|
+
margin-inline-start: calc(var(--gr-border-width) * -0.5);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Подпись и пояснение встают в колонку рядом с маркером (сама колонка —
|
|
219
|
+
// у .gr-step-body всегда); первая строка — по центру маркера.
|
|
220
|
+
#{$s} .gr-step-body {
|
|
221
|
+
gap: calc(var(--gr-ui-gap) * 0.25);
|
|
222
|
+
padding-block-start: calc((var(--gr-step-marker-size) - 1.3em) / 2);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@include gr-steps-vertical('.gr-steps-vertical');
|
|
227
|
+
|
|
228
|
+
// Столбиком ниже порога, рядом — от порога: суффикс называет порог,
|
|
229
|
+
// как у .gr-table-stack-md. -md — колонка, пока окно уже 768px;
|
|
230
|
+
// -cmd — пока уже 768px ближайший предок с .gr-cq. Разметка одна на оба
|
|
231
|
+
// вида: подпись и пояснение — в .gr-step-body.
|
|
232
|
+
@each $bp-name, $bp-value in bp.$gr-breakpoints {
|
|
233
|
+
@media (width < $bp-value) {
|
|
234
|
+
@include gr-steps-vertical('.gr-steps-stack-#{$bp-name}');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@include cq.gr-container-below($bp-name) {
|
|
238
|
+
@include gr-steps-vertical('.gr-steps-stack-c#{$bp-name}');
|
|
239
|
+
}
|
|
197
240
|
}
|
package/scss/_table.scss
CHANGED
|
@@ -6,12 +6,18 @@
|
|
|
6
6
|
//
|
|
7
7
|
// Ресет опционален, поэтому border-collapse задаётся здесь: без него
|
|
8
8
|
// у ячеек остались бы двойные линии и зазоры border-spacing.
|
|
9
|
+
//
|
|
10
|
+
// Таблица внутри .gr-prose оформлена теми же правилами: класс на <table>
|
|
11
|
+
// редактор не поставит. Селекторы прозы — под :where(), с нулевым весом:
|
|
12
|
+
// варианты (.gr-table-compact и другие) на такой таблице по-прежнему
|
|
13
|
+
// сильнее базы.
|
|
9
14
|
|
|
10
15
|
@use 'sass:string';
|
|
11
16
|
@use 'griffincss-core/scss/breakpoints' as bp;
|
|
12
17
|
@use 'griffincss-core/scss/container-mixins' as cq;
|
|
13
18
|
|
|
14
|
-
.gr-table
|
|
19
|
+
.gr-table,
|
|
20
|
+
:where(.gr-prose table) {
|
|
15
21
|
inline-size: 100%;
|
|
16
22
|
border-collapse: collapse;
|
|
17
23
|
color: var(--gr-color-text);
|
|
@@ -19,7 +25,8 @@
|
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
.gr-table th,
|
|
22
|
-
.gr-table td
|
|
28
|
+
.gr-table td,
|
|
29
|
+
:where(.gr-prose table :is(th, td)) {
|
|
23
30
|
padding-block: calc(var(--gr-gap) * 0.5);
|
|
24
31
|
padding-inline: calc(var(--gr-gap) * 0.75);
|
|
25
32
|
border-block-end: var(--gr-border-width) solid var(--gr-color-border);
|
|
@@ -27,24 +34,28 @@
|
|
|
27
34
|
vertical-align: top;
|
|
28
35
|
}
|
|
29
36
|
|
|
30
|
-
.gr-table th
|
|
37
|
+
.gr-table th,
|
|
38
|
+
:where(.gr-prose table th) {
|
|
31
39
|
color: var(--gr-color-text-secondary);
|
|
32
40
|
font-size: 0.875rem;
|
|
33
41
|
font-weight: 600;
|
|
34
42
|
white-space: nowrap;
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
.gr-table thead th
|
|
45
|
+
.gr-table thead th,
|
|
46
|
+
:where(.gr-prose table thead th) {
|
|
38
47
|
border-block-end: calc(var(--gr-border-width) * 2) solid var(--gr-color-border-strong);
|
|
39
48
|
}
|
|
40
49
|
|
|
41
|
-
.gr-table tfoot td
|
|
50
|
+
.gr-table tfoot td,
|
|
51
|
+
:where(.gr-prose table tfoot td) {
|
|
42
52
|
border-block-end: 0;
|
|
43
53
|
color: var(--gr-color-text-secondary);
|
|
44
54
|
font-size: 0.875rem;
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
.gr-table caption
|
|
57
|
+
.gr-table caption,
|
|
58
|
+
:where(.gr-prose table caption) {
|
|
48
59
|
padding-block-end: calc(var(--gr-gap) * 0.5);
|
|
49
60
|
color: var(--gr-color-text-secondary);
|
|
50
61
|
font-size: 0.875rem;
|
package/scss/griffincss-ui.scss
CHANGED
|
@@ -46,6 +46,16 @@
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// Слайды своей ширины: лента историй, полоса тегов, ряд логотипов. Ширину
|
|
50
|
+
// даёт содержимое — аватар, атрибуты width/height картинки, текст кнопки;
|
|
51
|
+
// утилита ширины на слайде доли 100% не перебьёт, основа здесь — flex-basis.
|
|
52
|
+
// Не сжимаются (flex-shrink: 0 базового правила): лишнее уходит в прокрутку.
|
|
53
|
+
// Стоит до суффиксных долей: .gr-track-auto .gr-track-3-lg — своя ширина
|
|
54
|
+
// на узком окне и три в ряд на широком.
|
|
55
|
+
.gr-track-auto > * {
|
|
56
|
+
flex-basis: auto;
|
|
57
|
+
}
|
|
58
|
+
|
|
49
59
|
// Доля слайда описана один раз: без суффикса — база, с суффиксом
|
|
50
60
|
// брейкпоинта — от ширины окна, с буквой c — от ширины ближайшего предка
|
|
51
61
|
// с .gr-cq (Этап 47d): виджет в слоте меряется слотом. Виджету дорожки
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// griffinjs.css подключается всегда ПОВЕРХ griffincss-ui.css, где он есть.
|
|
9
9
|
//
|
|
10
10
|
// Оформление привязывается к состояниям, а не к классам, которые JS
|
|
11
|
-
// добавляет: [data-gr-state="open"], .gr-
|
|
11
|
+
// добавляет: [data-gr-state="open"], .gr-track > [aria-current],
|
|
12
12
|
// var(--gr-progress). Движение — здесь, в CSS; JS transform и opacity
|
|
13
13
|
// не пишет никогда (инварианты слоя — docs/griffinjs-architecture.html).
|
|
14
14
|
//
|
package/src/griffincss-ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Griffincss UI — Runtime v0.
|
|
2
|
+
* Griffincss UI — Runtime v0.27.1
|
|
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.
|
|
53
|
+
var VERSION = '0.27.1';
|
|
54
54
|
|
|
55
55
|
var OVERLAY_ATTR = 'data-gr-overlay-close';
|
|
56
56
|
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
: closest(trigger, DISMISSIBLE);
|
|
235
235
|
|
|
236
236
|
if (!target) {
|
|
237
|
-
warn('
|
|
237
|
+
warn('close button has nothing to close: no data-gr-dismiss target and no enclosing message');
|
|
238
238
|
return true;
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -343,8 +343,8 @@
|
|
|
343
343
|
var urgent = options.assertive === undefined ? status === 'danger' : !!options.assertive;
|
|
344
344
|
|
|
345
345
|
if (status && !options.title) {
|
|
346
|
-
warn('
|
|
347
|
-
+ '
|
|
346
|
+
warn('toast with status "' + status + '" has no title: the status is shown by colour alone, '
|
|
347
|
+
+ 'which is lost in greyscale print and to colour-blind readers');
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
var node = buildToast(text, options, status);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* GriffinJS — Core v0.
|
|
2
|
+
* GriffinJS — Core v0.27.1
|
|
3
3
|
* Опциональный слой виджетов с состоянием поверх Griffincss: слайдер,
|
|
4
4
|
* галерея, лайтбокс, параллакс, мегаменю. Подключается одной строкой
|
|
5
5
|
* и одним файлом; страница без него — законное и рабочее состояние.
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
})(function () {
|
|
46
46
|
'use strict';
|
|
47
47
|
|
|
48
|
-
var VERSION = '0.
|
|
48
|
+
var VERSION = '0.27.1';
|
|
49
49
|
|
|
50
50
|
// Реестры. Модуль зовёт defineEngine/defineWidget; ядро — единственное
|
|
51
51
|
// место, которое знает, как их применить.
|
|
@@ -84,13 +84,13 @@
|
|
|
84
84
|
if (typeof opts === 'function') { factory = opts; opts = null; }
|
|
85
85
|
|
|
86
86
|
if (typeof name !== 'string' || !name) {
|
|
87
|
-
throw new Error('GriffinJS: ' + kind + '
|
|
87
|
+
throw new Error('GriffinJS: ' + kind + ' without a name');
|
|
88
88
|
}
|
|
89
89
|
if (typeof factory !== 'function') {
|
|
90
|
-
throw new Error('GriffinJS: ' + kind + '
|
|
90
|
+
throw new Error('GriffinJS: ' + kind + ' "' + name + '" is not a function');
|
|
91
91
|
}
|
|
92
92
|
if (registry[name]) {
|
|
93
|
-
throw new Error('GriffinJS: ' + kind + '
|
|
93
|
+
throw new Error('GriffinJS: ' + kind + ' "' + name + '" is already registered');
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
if (opts && opts.needs) needs(name, opts.needs);
|
|
@@ -101,11 +101,11 @@
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
function defineEngine(name, opts, factory) {
|
|
104
|
-
return define(engines, '
|
|
104
|
+
return define(engines, 'engine', name, opts, factory);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function defineWidget(name, opts, factory) {
|
|
108
|
-
return define(widgets, '
|
|
108
|
+
return define(widgets, 'widget', name, opts, factory);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
// Проверка сборки на старте: модуль подключён, а часть, которую он берёт
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
// Зависимостью бывает и часть G (track, anchor), и целый модуль:
|
|
125
125
|
// галерея строится поверх слайдера.
|
|
126
126
|
if (!api[dep] && !widgets[dep] && !engines[dep]) {
|
|
127
|
-
warn('
|
|
127
|
+
warn('"' + names[i] + '" does not work without griffinjs-' + dep + '.js');
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
// два слайдера на одной дорожке — ошибка автора, а не два состояния.
|
|
229
229
|
function mount(el, name, opts) {
|
|
230
230
|
if (!el || !widgets[name]) {
|
|
231
|
-
warn('
|
|
231
|
+
warn('widget "' + name + '" is not registered');
|
|
232
232
|
return null;
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
record.instance = widgets[name](el, opts, api) || {};
|
|
245
245
|
} catch (e) {
|
|
246
246
|
mounted.splice(mounted.indexOf(record), 1);
|
|
247
|
-
warn('
|
|
247
|
+
warn('widget "' + name + '" failed to mount: ' + (e && e.message));
|
|
248
248
|
return null;
|
|
249
249
|
}
|
|
250
250
|
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
if (config.fields && config.fields.src) return request();
|
|
63
63
|
|
|
64
64
|
warned[name] = true;
|
|
65
|
-
G.warn('
|
|
65
|
+
G.warn('field "' + name + '" is not loaded: include griffinjs-fields.js or set GriffinJS.config.fields');
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
function settle(event) {
|
|
86
86
|
if (event.type === 'error') {
|
|
87
87
|
ok = false;
|
|
88
|
-
G.warn('
|
|
88
|
+
G.warn('fields bundle failed to load: ' + event.target.src + '; fields stay without the script');
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
if (--left) return;
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* состояние, только physical.
|
|
21
21
|
*
|
|
22
22
|
* JS пишет только aria-*, inert, --gr-progress и --gr-snap (снап-точки
|
|
23
|
-
* по страницам); оформление активного слайда — .gr-
|
|
23
|
+
* по страницам); оформление активного слайда — .gr-track > [aria-current] в CSS.
|
|
24
24
|
*/
|
|
25
25
|
(function (G) {
|
|
26
26
|
'use strict';
|
|
@@ -542,7 +542,7 @@
|
|
|
542
542
|
var factory = G.engines[o.engine];
|
|
543
543
|
|
|
544
544
|
if (!factory) {
|
|
545
|
-
G.warn('
|
|
545
|
+
G.warn('engine "' + o.engine + '" is not registered; the track will not move');
|
|
546
546
|
} else {
|
|
547
547
|
engine = factory(api, el, o) || null;
|
|
548
548
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
var attrs = G.recorder();
|
|
33
33
|
var events = G.listeners();
|
|
34
34
|
|
|
35
|
-
if (!(max > 0)) throw new Error('
|
|
35
|
+
if (!(max > 0)) throw new Error('the field has no maxlength: nothing to count');
|
|
36
36
|
|
|
37
37
|
var out = o.out ? document.querySelector(o.out) : null;
|
|
38
38
|
var created = false;
|
|
@@ -235,7 +235,7 @@
|
|
|
235
235
|
var native = el.getAttribute('type');
|
|
236
236
|
var mode = MODES[native];
|
|
237
237
|
|
|
238
|
-
if (!mode) throw new Error('
|
|
238
|
+
if (!mode) throw new Error('needs type="date", "time" or "datetime-local"');
|
|
239
239
|
|
|
240
240
|
var attrs = G.recorder();
|
|
241
241
|
var events = G.listeners(); // на всё время жизни
|
|
@@ -797,7 +797,7 @@
|
|
|
797
797
|
var other = target && G.mount(target, 'datetime');
|
|
798
798
|
|
|
799
799
|
if (other) { peer = other; role = 'from'; other.pair(api); push(); }
|
|
800
|
-
else G.warn('datetime:
|
|
800
|
+
else G.warn('datetime: the "to" field is not found: ' + o.to);
|
|
801
801
|
}
|
|
802
802
|
|
|
803
803
|
return api;
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
G.defineWidget('file', function (el, opts) {
|
|
78
78
|
var o = G.merge(DEFAULTS, opts);
|
|
79
79
|
|
|
80
|
-
if (typeof DataTransfer !== 'function') throw new Error('
|
|
80
|
+
if (typeof DataTransfer !== 'function') throw new Error('without DataTransfer a single file cannot be removed from the selection');
|
|
81
81
|
|
|
82
82
|
var attrs = G.recorder();
|
|
83
83
|
var events = G.listeners();
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
// разобрался бы как пара «00: 00», поэтому без ключа берётся строка как есть.
|
|
164
164
|
var format = o.format ? String(o.format) : (el.getAttribute('data-gr-mask') || '').trim();
|
|
165
165
|
|
|
166
|
-
if (!format) throw new Error('
|
|
166
|
+
if (!format) throw new Error('the mask has no format');
|
|
167
167
|
|
|
168
168
|
var tokens;
|
|
169
169
|
var last = null; // последнее записанное значение
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
G.defineWidget('otp', function (el) {
|
|
36
36
|
var cells = el.querySelectorAll('input');
|
|
37
37
|
|
|
38
|
-
if (!cells.length) throw new Error('
|
|
38
|
+
if (!cells.length) throw new Error('no <input> cells inside');
|
|
39
39
|
|
|
40
40
|
var attrs = G.recorder();
|
|
41
41
|
var events = G.listeners();
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
var input = el.querySelector('input');
|
|
94
94
|
var locale = lang();
|
|
95
95
|
|
|
96
|
-
if (!input) throw new Error('
|
|
96
|
+
if (!input) throw new Error('the phone field has no <input>');
|
|
97
97
|
|
|
98
98
|
var created = []; // позиции, добавленные из таблицы
|
|
99
99
|
var texts = []; // [позиция, подпись автора] — для destroy
|
|
@@ -142,11 +142,11 @@
|
|
|
142
142
|
// Без country первой стоит первая по алфавиту языка страницы —
|
|
143
143
|
// на русской это Австралия, +61. Угадывать страну за автора виджет
|
|
144
144
|
// не берётся: ошибся бы тише, чем сейчас. Но и молчать не должен.
|
|
145
|
-
if (!o.country) G.warn('
|
|
145
|
+
if (!o.country) G.warn('phone: no country set, the first one alphabetically is used; set country');
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
if (!options().length) {
|
|
149
|
-
G.warn('
|
|
149
|
+
G.warn('phone: the code list is empty; list the <option>s yourself or include griffinjs-countries.js');
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
// Подписи: флаг + имя в языке страницы + код. Только там, где есть ISO
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
var display = el.querySelector('.gr-rating');
|
|
38
38
|
var radios = el.querySelectorAll('input[type="radio"]');
|
|
39
39
|
|
|
40
|
-
if (!display || !radios.length) throw new Error('
|
|
40
|
+
if (!display || !radios.length) throw new Error('needs .gr-rating and <input type="radio"> inside');
|
|
41
41
|
|
|
42
42
|
var attrs = G.recorder();
|
|
43
43
|
var events = G.listeners();
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
G.defineWidget('validate', function (el, opts) {
|
|
48
|
-
if (String(el.tagName).toLowerCase() !== 'form') throw new Error('
|
|
48
|
+
if (String(el.tagName).toLowerCase() !== 'form') throw new Error('needs a <form>');
|
|
49
49
|
|
|
50
50
|
var o = G.merge(DEFAULTS, opts);
|
|
51
51
|
var attrs = G.recorder();
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Источник — адрес с {q} (ответ — JSON: массив строк или объектов
|
|
9
9
|
* {value, label, href, group, id}, либо {items: […]}) или функция
|
|
10
10
|
* через JS: GriffinJS.mount(el, 'combobox', { source: (q, signal) => Promise }).
|
|
11
|
+
* С флагом navigate выбор позиции переходит по её href — только http(s).
|
|
11
12
|
* Рендер позиции подменяется render(item) → узел.
|
|
12
13
|
*
|
|
13
14
|
* База без JS — само поле: форма поиска отправляется Enter, как всегда.
|
|
@@ -140,12 +141,12 @@
|
|
|
140
141
|
|
|
141
142
|
var input = el.querySelector('input');
|
|
142
143
|
|
|
143
|
-
if (!input) throw new Error('
|
|
144
|
+
if (!input) throw new Error('the combobox has no input');
|
|
144
145
|
|
|
145
146
|
var choice = o.multiple ? el.querySelector('select[multiple]') : null;
|
|
146
147
|
|
|
147
|
-
if (o.multiple && !choice) throw new Error('
|
|
148
|
-
if (o.free && !choice) { G.warn('
|
|
148
|
+
if (o.multiple && !choice) throw new Error('multiple needs a <select multiple> inside');
|
|
149
|
+
if (o.free && !choice) { G.warn('combobox: free makes no sense without multiple; flag ignored'); o.free = false; }
|
|
149
150
|
|
|
150
151
|
var list = el.querySelector('[role="listbox"]');
|
|
151
152
|
var created = false;
|
|
@@ -276,7 +277,7 @@
|
|
|
276
277
|
return response.json();
|
|
277
278
|
});
|
|
278
279
|
} else {
|
|
279
|
-
G.warn('
|
|
280
|
+
G.warn('combobox: no source (src or source)');
|
|
280
281
|
return;
|
|
281
282
|
}
|
|
282
283
|
|
|
@@ -292,7 +293,7 @@
|
|
|
292
293
|
render(query, found);
|
|
293
294
|
}, function (error) {
|
|
294
295
|
if (error && error.name === 'AbortError') return;
|
|
295
|
-
G.warn('
|
|
296
|
+
G.warn('combobox: request failed: ' + (error && error.message));
|
|
296
297
|
});
|
|
297
298
|
}
|
|
298
299
|
|
|
@@ -440,11 +441,23 @@
|
|
|
440
441
|
close();
|
|
441
442
|
G.emit('griffin:select', input, { item: item, index: index, input: input });
|
|
442
443
|
|
|
443
|
-
if (o.navigate && item.href && typeof location !== 'undefined')
|
|
444
|
+
if (o.navigate && item.href && typeof location !== 'undefined') navigate(item.href);
|
|
444
445
|
|
|
445
446
|
return api;
|
|
446
447
|
}
|
|
447
448
|
|
|
449
|
+
// Переход — только по http(s): href приходит из ответа источника,
|
|
450
|
+
// и javascript: исполнился бы в origin страницы. Выбор при отказе
|
|
451
|
+
// остаётся — значение в поле, событие ушло.
|
|
452
|
+
function navigate(href) {
|
|
453
|
+
var url = null;
|
|
454
|
+
|
|
455
|
+
try { url = new URL(href, document.baseURI); } catch (e) { /* не адрес */ }
|
|
456
|
+
|
|
457
|
+
if (url && /^https?:$/.test(url.protocol)) location.href = href;
|
|
458
|
+
else G.warn('combobox: navigation refused: ' + href);
|
|
459
|
+
}
|
|
460
|
+
|
|
448
461
|
// --- События --------------------------------------------------------------
|
|
449
462
|
|
|
450
463
|
function onInput() { query(); }
|