@boobooking/dashboard-ui-components 0.14.0 → 0.15.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/README.md +286 -114
- package/dist/index.js +906 -717
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,42 +65,22 @@ Vue не ниже 3.5, ESM, сборщик, умеющий импорт CSS из
|
|
|
65
65
|
Tailwind, `@tailwindcss/forms`, Inertia и какие-либо токены в CSS приложения
|
|
66
66
|
пакету не нужны.
|
|
67
67
|
|
|
68
|
-
Меню `DropdownButtonWithAction`
|
|
69
|
-
|
|
68
|
+
Меню `DropdownButtonWithAction` и `HamburgerMenu`, список `SelectSingle` и
|
|
69
|
+
календари `SelectDateInterval` стоят на Popover API браузера: Safari 17+,
|
|
70
|
+
Chrome 114+, Firefox 125+. В браузерах старше меню, список и календари
|
|
71
|
+
видны в потоке всегда.
|
|
70
72
|
|
|
71
73
|
## Компоненты
|
|
72
74
|
|
|
73
|
-
Пакет экспортирует
|
|
74
|
-
`
|
|
75
|
-
`
|
|
76
|
-
`
|
|
75
|
+
Пакет экспортирует пятнадцать компонентов: `Dot`, `RussianMobileFilter`,
|
|
76
|
+
`Search`, `SelectDateInterval`, `SelectSingle`, `SmallBadge`,
|
|
77
|
+
`ErrorMessages`, `DownloadLink`, `ConfirmationModal`,
|
|
78
|
+
`DropdownButtonWithAction`, `HamburgerMenu`, `DataTable`,
|
|
77
79
|
`NavigationMenuElement`, `PageCard`, `NotificationMessage` и плагин
|
|
78
80
|
`dashboardUi`. В архив пакета (`files: ["dist"]`) исходники не попадают,
|
|
79
81
|
поэтому контракт каждого компонента — здесь и в playground, а не в исходном
|
|
80
82
|
коде.
|
|
81
83
|
|
|
82
|
-
### Popup
|
|
83
|
-
|
|
84
|
-
Всплывающее меню с оверлеем, закрывающим по клику вне, и переходом на
|
|
85
|
-
открытие/закрытие. Другие компоненты пакета используют его как обёртку над
|
|
86
|
-
своим содержимым — некоторые напрямую, некоторые через внутренние
|
|
87
|
-
компоненты.
|
|
88
|
-
|
|
89
|
-
<popup v-model="isOpen" align="right">
|
|
90
|
-
…содержимое меню…
|
|
91
|
-
</popup>
|
|
92
|
-
|
|
93
|
-
| Проп | Тип | По умолчанию | Описание |
|
|
94
|
-
| --- | --- | --- | --- |
|
|
95
|
-
| `modelValue` | `Boolean` | `false` | Открыто ли меню |
|
|
96
|
-
| `align` | `String` | `"left"` | `"left"` или `"right"` — с какой стороны прижать меню |
|
|
97
|
-
|
|
98
|
-
Событие: `update:modelValue` — при каждом открытии и закрытии, включая клик по
|
|
99
|
-
оверлею.
|
|
100
|
-
|
|
101
|
-
У `Popup` нет события `changed`, и это не пропуск — см. раздел
|
|
102
|
-
«Почему у Popup и Dot нет события changed».
|
|
103
|
-
|
|
104
84
|
### Dot
|
|
105
85
|
|
|
106
86
|
Индикатор-точка: красная или зелёная, с пульсацией или без.
|
|
@@ -113,26 +93,7 @@ Chrome 114+, Firefox 125+. В браузерах старше меню видн
|
|
|
113
93
|
| `withPulse` | `Boolean` | `false` | Добавляет анимацию пульсации |
|
|
114
94
|
|
|
115
95
|
Событий нет. Значения у `Dot` тоже нет — см. раздел
|
|
116
|
-
«Почему у
|
|
117
|
-
|
|
118
|
-
### PickDay
|
|
119
|
-
|
|
120
|
-
Поле выбора одной даты на Pikaday, с ластиком очистки. Pikaday загружается
|
|
121
|
-
в браузере при монтировании компонента, а не при загрузке пакета, поэтому
|
|
122
|
-
календарь появляется, когда загрузка закончится.
|
|
123
|
-
|
|
124
|
-
<pick-day v-model="date" placeholder-text="от" />
|
|
125
|
-
|
|
126
|
-
| Проп | Тип | По умолчанию | Описание |
|
|
127
|
-
| --- | --- | --- | --- |
|
|
128
|
-
| `modelValue` | `String` | `""` | Текущая дата |
|
|
129
|
-
| `withEraser` | `Boolean` | `true` | Показывать ли ластик очистки |
|
|
130
|
-
| `placeholderText` | `String` | `""` | Текст подсказки в пустом поле |
|
|
131
|
-
| `lang` | `String` | язык плагина | `"ru"` или `"en"`; календарь берёт язык при монтировании |
|
|
132
|
-
|
|
133
|
-
События: `update:modelValue` — при выборе даты в календаре и при очистке
|
|
134
|
-
(пустой строкой); `changed` — в тех же двух случаях, для использования наравне
|
|
135
|
-
с остальными фильтрами.
|
|
96
|
+
«Почему у Dot нет события changed».
|
|
136
97
|
|
|
137
98
|
### RussianMobileFilter
|
|
138
99
|
|
|
@@ -179,7 +140,10 @@ Chrome 114+, Firefox 125+. В браузерах старше меню видн
|
|
|
179
140
|
|
|
180
141
|
### SelectDateInterval
|
|
181
142
|
|
|
182
|
-
|
|
143
|
+
Два поля даты под одним заголовком — интервал дат «от» и «до». Дата
|
|
144
|
+
выбирается в календаре Pikaday, у каждого поля — ластик очистки. Pikaday
|
|
145
|
+
загружается в браузере при монтировании компонента, а не при загрузке
|
|
146
|
+
пакета, поэтому календари появляются, когда загрузка закончится.
|
|
183
147
|
|
|
184
148
|
<select-date-interval
|
|
185
149
|
header="Период"
|
|
@@ -199,9 +163,20 @@ Chrome 114+, Firefox 125+. В браузерах старше меню видн
|
|
|
199
163
|
| `isLoading` | `Boolean` | `false` | Индикатор загрузки в заголовке |
|
|
200
164
|
| `lang` | `String` | язык плагина | `"ru"` или `"en"`; действует и на подсказки полей, и на оба календаря |
|
|
201
165
|
|
|
202
|
-
События: `update:dateFrom`, `update:dateTo` — на каждый выбор
|
|
203
|
-
соответствующем
|
|
204
|
-
|
|
166
|
+
События: `update:dateFrom`, `update:dateTo` — на каждый выбор даты
|
|
167
|
+
в соответствующем поле и на его очистку ластиком (пустой строкой);
|
|
168
|
+
`changed` — когда новое значение отличается от переданного пропса
|
|
169
|
+
(отдельно для каждой из двух дат).
|
|
170
|
+
|
|
171
|
+
Клик по любому месту поля открывает его календарь. Календарь открывается
|
|
172
|
+
в верхнем слое браузера (Popover API): его не обрезает обёртка
|
|
173
|
+
с прокруткой. Он открывается под полем, левым краем по левому краю поля.
|
|
174
|
+
Не поместившись снизу, он открывается вверх, если сверху места больше;
|
|
175
|
+
не поместившись справа — правым краем по правому краю поля, если слева
|
|
176
|
+
места больше. Выбор даты, клик вне календаря, Escape, прокрутка страницы
|
|
177
|
+
и изменение размера окна закрывают календарь. Клик вне доходит до элемента
|
|
178
|
+
под курсором, поэтому календарь «до» открывается тем же кликом, что
|
|
179
|
+
закрывает «от».
|
|
205
180
|
|
|
206
181
|
### SelectSingle
|
|
207
182
|
|
|
@@ -238,6 +213,17 @@ Chrome 114+, Firefox 125+. В браузерах старше меню видн
|
|
|
238
213
|
ставит фокус на него, стрелки продолжают от пункта под курсором. Подсвечен
|
|
239
214
|
всегда один пункт — тот, на который последними указали клавиатура или мышь.
|
|
240
215
|
|
|
216
|
+
Список открывается в верхнем слое браузера (Popover API): его не обрезает
|
|
217
|
+
обёртка с прокруткой. Он открывается под полем, левым краем по левому
|
|
218
|
+
краю поля. Не поместившись снизу, он открывается вверх, если сверху места
|
|
219
|
+
больше; не поместившись справа — правым краем по правому краю поля, если
|
|
220
|
+
слева места больше. Длинный список ограничен высотой до края окна
|
|
221
|
+
и прокручивается внутри. Клик вне списка закрывает его и доходит до
|
|
222
|
+
элемента под курсором: соседний фильтр открывается тем же кликом.
|
|
223
|
+
Прокрутка страницы и изменение размера окна закрывают список, прокрутка
|
|
224
|
+
внутри списка — нет. Открытие другого списка, календаря или меню
|
|
225
|
+
закрывает предыдущее.
|
|
226
|
+
|
|
241
227
|
### SmallBadge
|
|
242
228
|
|
|
243
229
|
Бейдж-пилюля с коротким текстом. Текст не переносится.
|
|
@@ -265,16 +251,6 @@ Chrome 114+, Firefox 125+. В браузерах старше меню видн
|
|
|
265
251
|
|
|
266
252
|
Событий нет.
|
|
267
253
|
|
|
268
|
-
### Closer
|
|
269
|
-
|
|
270
|
-
Кнопка-крестик закрытия. Размер и положение задаёт приложение классами на
|
|
271
|
-
корне: без классов размера крестик получает размер SVG по умолчанию
|
|
272
|
-
(300×300).
|
|
273
|
-
|
|
274
|
-
<closer class="absolute top-0 right-0 w-8 h-8" @clicked="close" />
|
|
275
|
-
|
|
276
|
-
Пропов нет. Событие: `clicked` — по клику.
|
|
277
|
-
|
|
278
254
|
### DownloadLink
|
|
279
255
|
|
|
280
256
|
Ссылка на файл в виде бейджа с иконкой скачивания. Кликабелен весь бейдж.
|
|
@@ -327,58 +303,71 @@ ConfirmationModal нет v-model».
|
|
|
327
303
|
|
|
328
304
|
### DropdownButtonWithAction
|
|
329
305
|
|
|
330
|
-
Кнопка
|
|
331
|
-
|
|
332
|
-
|
|
306
|
+
Кнопка из списка действий `actions`. Первое действие — основная кнопка,
|
|
307
|
+
остальные — меню за стрелкой справа. Одно действие — кнопка без стрелки;
|
|
308
|
+
без действий компонент ничего не рисует.
|
|
333
309
|
|
|
334
310
|
<dropdown-button-with-action
|
|
335
311
|
v-model="menuIsOpen"
|
|
336
312
|
:actions="[
|
|
313
|
+
{ label: 'Редактировать', href: route('user.edit', { user: row.getId() }) },
|
|
337
314
|
{ label: 'Поменять пароль', href: route('user.password.edit', { user: row.getId() }) },
|
|
338
|
-
{ label: 'Удалить',
|
|
315
|
+
{ label: 'Удалить', color: 'red', onSelect: () => prepareUserDelete(row) },
|
|
339
316
|
]"
|
|
340
|
-
|
|
341
|
-
<template #button>…основное действие…</template>
|
|
342
|
-
</dropdown-button-with-action>
|
|
317
|
+
/>
|
|
343
318
|
|
|
344
319
|
| Проп | Тип | По умолчанию | Описание |
|
|
345
320
|
| --- | --- | --- | --- |
|
|
346
|
-
| `actions` | `Array` | `[]` |
|
|
321
|
+
| `actions` | `Array` | `[]` | Действия, см. ниже |
|
|
347
322
|
| `modelValue` | `Boolean` | `false` | Открыто ли меню |
|
|
348
323
|
| `lang` | `String` | язык плагина | `"ru"` или `"en"` |
|
|
349
324
|
|
|
350
|
-
|
|
325
|
+
Действие — объект одной из двух форм: переход (`href` без `onSelect`) или
|
|
351
326
|
действие (`onSelect` без `href`). Поле со значением `undefined` считается
|
|
352
327
|
отсутствующим.
|
|
353
328
|
|
|
354
329
|
| Поле | Тип | Описание |
|
|
355
330
|
| --- | --- | --- |
|
|
356
|
-
| `label` | `String`, обязательно | Текст пункта |
|
|
331
|
+
| `label` | `String`, обязательно | Текст кнопки или пункта меню |
|
|
357
332
|
| `href` | `String` | Переход: обычный клик уходит в `navigate` плагина `dashboardUi`, клик с Cmd/Ctrl/Shift и средней кнопкой — браузеру; без `navigate` — обычная ссылка |
|
|
358
|
-
| `onSelect` | `Function` | Действие: вызывается без аргументов
|
|
359
|
-
| `
|
|
333
|
+
| `onSelect` | `Function` | Действие: вызывается без аргументов |
|
|
334
|
+
| `color` | `"yellow"` или `"red"` | Цвет; без поля — обычный |
|
|
335
|
+
|
|
336
|
+
Основная кнопка работает как пункт меню: переход — ссылка, действие —
|
|
337
|
+
кнопка, и `onSelect` вызывает сам компонент — по клику, Enter и пробелу.
|
|
338
|
+
Своего события клика у кнопки нет: странице не нужно ловить клик и
|
|
339
|
+
разбираться в разметке компонента.
|
|
340
|
+
|
|
341
|
+
Цвет первого действия красит основную кнопку вместе со стрелкой, цвет
|
|
342
|
+
пункта меню — только этот пункт. Обычная кнопка — белая с серой рамкой,
|
|
343
|
+
жёлтая и красная — светлый фон, рамка и текст своего цвета. Обычный пункт
|
|
344
|
+
меню — серый текст, при подсветке серый фон; жёлтый и красный — текст
|
|
345
|
+
своего цвета, при подсветке светлый фон того же цвета.
|
|
360
346
|
|
|
361
347
|
Неверный список Vue отмечает предупреждением о пропе в режиме разработки,
|
|
362
348
|
а компонент не падает: элементы-необъекты пропускает, кнопка без функции
|
|
363
|
-
`onSelect`
|
|
349
|
+
`onSelect` по клику ничего не вызывает, пункт без неё только закрывает
|
|
350
|
+
меню. `null` — пустой список.
|
|
364
351
|
|
|
365
|
-
Вид пунктов задаёт компонент: страница передаёт данные, а не
|
|
366
|
-
и классов
|
|
367
|
-
|
|
368
|
-
|
|
352
|
+
Вид кнопки и пунктов задаёт компонент: страница передаёт данные, а не
|
|
353
|
+
разметку, и классов не даёт. Слота `button` и поля `danger` нет с версии
|
|
354
|
+
0.15.0 — см. «Обновление с 0.14»; слота `actions` — с 0.14.0, см.
|
|
355
|
+
«Обновление с 0.13».
|
|
369
356
|
|
|
370
357
|
Событие: `update:modelValue` — только когда меню открыл или закрыл сам
|
|
371
358
|
компонент или браузер: клик по стрелке, клик вне меню, Escape, клик
|
|
372
|
-
по пункту меню, прокрутка, изменение размера
|
|
359
|
+
по пункту меню, прокрутка, изменение размера окна, а ещё пропажа открытого
|
|
360
|
+
меню, когда действий осталось меньше двух. Значение, пришедшее
|
|
373
361
|
от родителя, компонент принимает молча: ответное событие вернуло бы
|
|
374
362
|
родителю его же решение. Без `v-model` меню работает само по себе.
|
|
375
363
|
|
|
376
364
|
Меню открывается в верхнем слое браузера (Popover API): его не обрезает
|
|
377
365
|
таблица с горизонтальной прокруткой, и оно стоит поверх страницы. Правый
|
|
378
|
-
край меню — по правому краю стрелки; меню открывается
|
|
379
|
-
где больше места, сужается у левого края
|
|
380
|
-
по любому пункту, прокруткой страницы или
|
|
381
|
-
окна. Открытие другого меню закрывает
|
|
366
|
+
край меню — по правому краю стрелки; меню открывается под стрелкой,
|
|
367
|
+
а если там не помещается — туда, где больше места, сужается у левого края
|
|
368
|
+
окна и закрывается кликом по любому пункту, прокруткой страницы или
|
|
369
|
+
таблицы и изменением размера окна. Открытие другого меню закрывает
|
|
370
|
+
предыдущее.
|
|
382
371
|
|
|
383
372
|
Пока меню открыто, стрелки вверх и вниз переводят фокус по пунктам и
|
|
384
373
|
страницу не прокручивают: вниз — на первый пункт, вверх — на последний,
|
|
@@ -388,6 +377,54 @@ ConfirmationModal нет v-model».
|
|
|
388
377
|
курсором. Подсвечен всегда один пункт — тот, на который последними указали
|
|
389
378
|
клавиатура или мышь.
|
|
390
379
|
|
|
380
|
+
### HamburgerMenu
|
|
381
|
+
|
|
382
|
+
Кнопка ☰ с меню из пунктов пропа `actions` — меню профиля в шапке
|
|
383
|
+
дашборда. Кнопку, панель и пункты рисует компонент, страница передаёт
|
|
384
|
+
только пункты. Без пунктов кнопки нет.
|
|
385
|
+
|
|
386
|
+
<hamburger-menu :actions="menuActions" />
|
|
387
|
+
|
|
388
|
+
import { router } from '@inertiajs/vue3';
|
|
389
|
+
|
|
390
|
+
computed: {
|
|
391
|
+
menuActions() {
|
|
392
|
+
return [
|
|
393
|
+
{ label: 'Администраторы', href: this.route('users') },
|
|
394
|
+
{ label: 'Поменять пароль', href: this.route('my.password.edit') },
|
|
395
|
+
{ label: 'Выйти', onSelect: () => router.delete(this.route('logout')) },
|
|
396
|
+
];
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
|
|
400
|
+
| Проп | Тип | По умолчанию | Описание |
|
|
401
|
+
| --- | --- | --- | --- |
|
|
402
|
+
| `actions` | `Array` | `[]` | Пункты меню — в том же формате, что у `DropdownButtonWithAction` |
|
|
403
|
+
| `lang` | `String` | язык плагина | `"ru"` или `"en"` |
|
|
404
|
+
|
|
405
|
+
Пункты, их проверка и вид — как у `DropdownButtonWithAction`: переход —
|
|
406
|
+
`{ label, href }`, действие — `{ label, onSelect }`, цвет —
|
|
407
|
+
`color: 'yellow'` или `color: 'red'`. Выход запросом DELETE — действие:
|
|
408
|
+
Inertia пакет не импортирует, `router.delete` вызывает страница.
|
|
409
|
+
|
|
410
|
+
Событий и `v-model` нет: меню открывают и закрывают кнопка, клик вне меню,
|
|
411
|
+
Escape, клик по пункту, прокрутка и изменение размера окна. Меню
|
|
412
|
+
открывается в верхнем слое браузера (Popover API), правым краем по правому
|
|
413
|
+
краю кнопки, под ней, а если там не помещается — туда, где больше места.
|
|
414
|
+
Открытие другого меню закрывает предыдущее.
|
|
415
|
+
|
|
416
|
+
Это исключение из правила «состояние, которое компонент меняет сам, — через
|
|
417
|
+
`v-model`»: шапке не нужно ни открывать меню извне, ни знать, открыто ли
|
|
418
|
+
оно. Меню строк таблицы на `DropdownButtonWithAction` страница держит под
|
|
419
|
+
`v-model`, чтобы знать, какая строка выбрана; у меню профиля такой нужды нет.
|
|
420
|
+
`v-model`, переданный на `<hamburger-menu>`, в контракт не входит. Атрибуты
|
|
421
|
+
с `<hamburger-menu>` — `class`, `style`, `data-*` — ложатся на обёртку
|
|
422
|
+
кнопки.
|
|
423
|
+
|
|
424
|
+
Клавиатура и мышь — как в меню `DropdownButtonWithAction`: пока меню
|
|
425
|
+
открыто, стрелки вверх и вниз переводят фокус по пунктам, Enter выбирает
|
|
426
|
+
пункт под фокусом; подсветка пункта — это фокус, и мышь ведёт тот же фокус.
|
|
427
|
+
|
|
391
428
|
### DataTable
|
|
392
429
|
|
|
393
430
|
Список данных: бейдж «Найдено X: N», таблица в карточке с горизонтальной
|
|
@@ -667,15 +704,16 @@ sm:rounded-lg`, `box-sizing: border-box`. Отступов у неё нет: ф
|
|
|
667
704
|
| `ConfirmationModal` — кнопка отмены | Отмена | Cancel |
|
|
668
705
|
| `DownloadLink` — подпись | Скачать | Download |
|
|
669
706
|
| `DropdownButtonWithAction` — подпись стрелки для скринридера | Открыть меню | Open menu |
|
|
670
|
-
| `
|
|
707
|
+
| `HamburgerMenu` — подпись кнопки для скринридера | Открыть меню | Open menu |
|
|
708
|
+
| `SelectDateInterval` — месяцы, дни недели, кнопки календарей | по-русски | in English |
|
|
671
709
|
| `SelectDateInterval` — подсказки полей | от / до | from / to |
|
|
672
710
|
| `DataTable` — пагинация | Предыдущая / Следующая / Показаны результаты X - Y из Z | Previous / Next / Showing X - Y of Z results |
|
|
673
711
|
| `PageCard` — доступное имя крестика | Назад | Back |
|
|
674
712
|
| `NotificationMessage` — подпись крестика для скринридера | Закрыть | Close |
|
|
675
713
|
|
|
676
714
|
Формат даты — `дд.мм.гггг` в обоих языках: это формат значения, а не текст.
|
|
677
|
-
Неделя начинается с понедельника.
|
|
678
|
-
монтировании: смена языка после монтирования в
|
|
715
|
+
Неделя начинается с понедельника. Календари `SelectDateInterval` берут язык
|
|
716
|
+
при монтировании: смена языка после монтирования в них не отражается.
|
|
679
717
|
|
|
680
718
|
## SSR
|
|
681
719
|
|
|
@@ -686,8 +724,8 @@ Inertia SSR), а серверная разметка гидратируется
|
|
|
686
724
|
- `PageCard` на сервере рисует крестик, только если задан `fallback-url`:
|
|
687
725
|
адрес возврата известен только в браузере, и крестик, ведущий на него,
|
|
688
726
|
появляется после монтирования;
|
|
689
|
-
- `
|
|
690
|
-
|
|
727
|
+
- `SelectDateInterval` загружает Pikaday в браузере при монтировании:
|
|
728
|
+
календари появляются, когда загрузка закончится;
|
|
691
729
|
- остальные компоненты рендерятся на сервере так же, как в браузере.
|
|
692
730
|
|
|
693
731
|
## Правила API пакета
|
|
@@ -706,9 +744,9 @@ Inertia SSR), а серверная разметка гидратируется
|
|
|
706
744
|
для него это и есть обычный `v-model`.
|
|
707
745
|
- Булев проп называется `is*`, если описывает состояние компонента
|
|
708
746
|
(`isRequired`, `isLoading`), и `with*`, если описывает необязательную
|
|
709
|
-
возможность (`
|
|
747
|
+
возможность (`withPulse` у `Dot`).
|
|
710
748
|
- Проп-перечисление — ограниченный набор строковых значений, как `color` у
|
|
711
|
-
`Dot` или `
|
|
749
|
+
`Dot` или `variant` у `DataTable`, — обязательно имеет `validator`,
|
|
712
750
|
отклоняющий значения вне списка.
|
|
713
751
|
- Компонент не падает ни на каком значении пропа. `null` и `undefined` там,
|
|
714
752
|
где ждут строку, объект или массив, он считает пустыми: пустой строкой,
|
|
@@ -727,8 +765,11 @@ Inertia SSR), а серверная разметка гидратируется
|
|
|
727
765
|
`followLink($event, href)` миксина `withNavigation`, который отдаёт его
|
|
728
766
|
`navigate` плагина. Ни Inertia, ни роутер пакет не импортирует. Исключение —
|
|
729
767
|
`DownloadLink`: это обычная ссылка браузера, скачивающая файл, и через
|
|
730
|
-
`navigate` она не идёт. Через `navigate` ходят `DataTable` (его пагинация)
|
|
731
|
-
`NavigationMenuElement
|
|
768
|
+
`navigate` она не идёт. Через `navigate` ходят `DataTable` (его пагинация),
|
|
769
|
+
`NavigationMenuElement`, основная кнопка-переход и пункты-переходы
|
|
770
|
+
`DropdownButtonWithAction` и пункты-переходы `HamburgerMenu`. Крестик
|
|
771
|
+
`PageCard` — кнопка, а не ссылка: адрес возврата он тоже отдаёт
|
|
772
|
+
`navigate`.
|
|
732
773
|
- Компонент обращается к `window`, `document` и другим API браузера только
|
|
733
774
|
в `mounted()`, `beforeUnmount()` и обработчиках событий; загрузка модуля,
|
|
734
775
|
`data()`, `computed` и рендер работают без браузера. Так пакет
|
|
@@ -736,31 +777,25 @@ Inertia SSR), а серверная разметка гидратируется
|
|
|
736
777
|
`tests/ssr.test.js` и `tests/hydration.test.js`: каждый экспортируемый
|
|
737
778
|
компонент обязан иметь фикстуру в `tests/ssrFixtures.js`.
|
|
738
779
|
|
|
739
|
-
## Почему у
|
|
780
|
+
## Почему у Dot нет события changed
|
|
740
781
|
|
|
741
782
|
`changed` означает не «значение изменилось», а «пользователь закончил
|
|
742
783
|
выбор, можно обновлять выдачу» — фильтры дашборда эмитят его как сигнал к
|
|
743
784
|
перезапросу данных.
|
|
744
785
|
|
|
745
|
-
У `
|
|
746
|
-
|
|
747
|
-
данные. Момент, когда выбор действительно завершён, отслеживает
|
|
748
|
-
компонент, который использует `Popup` — сам или через внутренние
|
|
749
|
-
компоненты пакета, — `changed` эмитит он.
|
|
750
|
-
|
|
751
|
-
У `Dot` события нет по другой причине: у него нет значения вообще, поэтому
|
|
752
|
-
эмитить не о чем.
|
|
786
|
+
У `Dot` такого момента нет: у него нет значения вообще, поэтому эмитить
|
|
787
|
+
не о чем.
|
|
753
788
|
|
|
754
|
-
Отсутствие `changed` у `
|
|
755
|
-
пропуск.
|
|
789
|
+
Отсутствие `changed` у `Dot` — сознательное решение, а не пропуск.
|
|
756
790
|
|
|
757
791
|
## Почему у ConfirmationModal нет v-model
|
|
758
792
|
|
|
759
793
|
Правило пакета — значение через `v-model` — относится к состоянию, которое
|
|
760
|
-
компонент меняет сам: `
|
|
761
|
-
выбор. `ConfirmationModal` свою видимость не меняет
|
|
762
|
-
сообщают родителю решение пользователя, а закрыть
|
|
763
|
-
на время запроса или открыть следующую — решает
|
|
794
|
+
компонент меняет сам: меню `DropdownButtonWithAction` закрывается по клику
|
|
795
|
+
вне, `SelectSingle` меняет выбор. `ConfirmationModal` свою видимость не меняет
|
|
796
|
+
никогда. Обе кнопки только сообщают родителю решение пользователя, а закрыть
|
|
797
|
+
модалку, оставить её открытой на время запроса или открыть следующую — решает
|
|
798
|
+
родитель.
|
|
764
799
|
|
|
765
800
|
`v-model` обещал бы двустороннюю связь, которой нет, поэтому видимость
|
|
766
801
|
передаётся пропом `isOpen`.
|
|
@@ -769,7 +804,7 @@ Inertia SSR), а серверная разметка гидратируется
|
|
|
769
804
|
|
|
770
805
|
npm run playground
|
|
771
806
|
|
|
772
|
-
Поднимает демо-страницы со всеми
|
|
807
|
+
Поднимает демо-страницы со всеми пятнадцатью компонентами в двух окружениях:
|
|
773
808
|
голом (без Tailwind и стилей приложения) и в окружении приложения (с
|
|
774
809
|
Tailwind, `@tailwindcss/forms` и типографикой, как у потребителя). Это
|
|
775
810
|
основной способ посмотреть, как компоненты выглядят и ведут себя, а не
|
|
@@ -785,6 +820,147 @@ Tailwind, `@tailwindcss/forms` и типографикой, как у потре
|
|
|
785
820
|
Правила номера телефона в `RussianMobileFilter` — российские; язык текстов
|
|
786
821
|
задаётся, см. «Языки».
|
|
787
822
|
|
|
823
|
+
## Обновление с 0.14
|
|
824
|
+
|
|
825
|
+
- Меню профиля в шапке переходит с `Popup` на `HamburgerMenu`: кнопку ☰,
|
|
826
|
+
панель и пункты рисует компонент, страница передаёт только пункты. Было:
|
|
827
|
+
|
|
828
|
+
<div class="relative">
|
|
829
|
+
<div>
|
|
830
|
+
<button
|
|
831
|
+
@click="menuDropdownOpen = !menuDropdownOpen"
|
|
832
|
+
:class="{ 'z-20': menuDropdownOpen }"
|
|
833
|
+
class="relative inline-flex items-center justify-center p-2 rounded-md text-gray-400 …"
|
|
834
|
+
aria-label="Main menu"
|
|
835
|
+
aria-expanded="false"
|
|
836
|
+
>
|
|
837
|
+
<svg class="h-6 w-6" …>…</svg>
|
|
838
|
+
</button>
|
|
839
|
+
</div>
|
|
840
|
+
<popup class="origin-top-right right-0" v-model="menuDropdownOpen" align="right">
|
|
841
|
+
<div class="mt-1 w-56 rounded-md shadow-lg bg-white ring-1 ring-black/5" role="menu" …>
|
|
842
|
+
<Link :href="route('users')" as="button" class="…" role="menuitem">Администраторы</Link>
|
|
843
|
+
<Link :href="route('logout')" method="delete" as="button" class="…" role="menuitem">Выйти</Link>
|
|
844
|
+
</div>
|
|
845
|
+
</popup>
|
|
846
|
+
</div>
|
|
847
|
+
|
|
848
|
+
Стало:
|
|
849
|
+
|
|
850
|
+
<hamburger-menu :actions="menuActions" />
|
|
851
|
+
|
|
852
|
+
import { router } from '@inertiajs/vue3';
|
|
853
|
+
|
|
854
|
+
computed: {
|
|
855
|
+
menuActions() {
|
|
856
|
+
return [
|
|
857
|
+
{ label: 'Администраторы', href: this.route('users') },
|
|
858
|
+
{ label: 'Выйти', onSelect: () => router.delete(this.route('logout')) },
|
|
859
|
+
];
|
|
860
|
+
},
|
|
861
|
+
},
|
|
862
|
+
|
|
863
|
+
Пункты собираются в `computed`: в шаблоне импорт `router` недоступен.
|
|
864
|
+
Выход запросом DELETE — действие с `router.delete`, тот же вызов, что
|
|
865
|
+
делал `<Link method="delete">`. `menuDropdownOpen` и импорт `Popup`
|
|
866
|
+
больше не нужны.
|
|
867
|
+
- Пункты-переходы `HamburgerMenu` — ссылки `<a href>`, а не `<Link>`:
|
|
868
|
+
обычный клик уходит в `navigate` плагина `dashboardUi` (для Inertia —
|
|
869
|
+
`router.visit`), Cmd-клик и средняя кнопка открывают новую вкладку. Без
|
|
870
|
+
`navigate` переход идёт полной загрузкой страницы — подключите его
|
|
871
|
+
к плагину (см. «Подключение к приложению»).
|
|
872
|
+
- `Popup`, `PickDay` и `Closer` больше не экспортируются: это внутренние
|
|
873
|
+
части `SelectSingle`, `SelectDateInterval` и `PageCard`. Импорт любого
|
|
874
|
+
из них ломает сборку: «… is not exported by …».
|
|
875
|
+
- Список `SelectSingle` и календари `SelectDateInterval` открываются
|
|
876
|
+
в верхнем слое браузера, как меню. Клик вне закрывает их и доходит до
|
|
877
|
+
элемента под курсором, прокрутка страницы закрывает, длинный список
|
|
878
|
+
прокручивается внутри. Без Popover API (Safari до 17, Chrome до 114,
|
|
879
|
+
Firefox до 125) они видны всегда.
|
|
880
|
+
- Меню `DropdownButtonWithAction` и `HamburgerMenu` открывается под
|
|
881
|
+
кнопкой, а вверх — только если снизу не помещается и сверху места
|
|
882
|
+
больше. В 0.14 меню в нижней половине окна открывалось вверх всегда.
|
|
883
|
+
- `DropdownButtonWithAction` строится из списка действий: первое действие —
|
|
884
|
+
основная кнопка, остальные — меню. Слота `button` нет: переданный слот
|
|
885
|
+
не рисуется, а в режиме разработки в консоль уходит предупреждение.
|
|
886
|
+
Отступы и шрифт основной кнопки задаёт компонент (`px-4 py-2 text-sm
|
|
887
|
+
font-medium`). Было:
|
|
888
|
+
|
|
889
|
+
<dropdown-button-with-action
|
|
890
|
+
:actions="[
|
|
891
|
+
{ label: 'Поменять пароль', href: route('user.password.edit', { user: row.getId() }) },
|
|
892
|
+
{ label: 'Удалить', danger: true, onSelect: () => prepareUserDelete(row) },
|
|
893
|
+
]"
|
|
894
|
+
>
|
|
895
|
+
<template v-slot:button>
|
|
896
|
+
<Link class="block px-4 py-2 text-sm font-medium text-gray-700" :href="route('user.edit', { user: row.getId() })">
|
|
897
|
+
Редактировать
|
|
898
|
+
</Link>
|
|
899
|
+
</template>
|
|
900
|
+
</dropdown-button-with-action>
|
|
901
|
+
|
|
902
|
+
Стало:
|
|
903
|
+
|
|
904
|
+
<dropdown-button-with-action
|
|
905
|
+
:actions="[
|
|
906
|
+
{ label: 'Редактировать', href: route('user.edit', { user: row.getId() }) },
|
|
907
|
+
{ label: 'Поменять пароль', href: route('user.password.edit', { user: row.getId() }) },
|
|
908
|
+
{ label: 'Удалить', color: 'red', onSelect: () => prepareUserDelete(row) },
|
|
909
|
+
]"
|
|
910
|
+
/>
|
|
911
|
+
|
|
912
|
+
- Кнопка без меню — одно действие. Было:
|
|
913
|
+
|
|
914
|
+
<dropdown-button-with-action>
|
|
915
|
+
<template v-slot:button>
|
|
916
|
+
<Link class="block px-4 py-2 text-sm font-medium text-gray-700" :href="showGroupLink(row)">
|
|
917
|
+
Посмотреть
|
|
918
|
+
</Link>
|
|
919
|
+
</template>
|
|
920
|
+
</dropdown-button-with-action>
|
|
921
|
+
|
|
922
|
+
Стало:
|
|
923
|
+
|
|
924
|
+
<dropdown-button-with-action :actions="[{ label: 'Посмотреть', href: showGroupLink(row) }]" />
|
|
925
|
+
|
|
926
|
+
- Основное действие-функция больше не ловится на корне компонента:
|
|
927
|
+
`onSelect` первого действия вызывает сам компонент — по клику, Enter и
|
|
928
|
+
пробелу. Было:
|
|
929
|
+
|
|
930
|
+
<dropdown-button-with-action
|
|
931
|
+
:actions="[{ label: 'Зафиксировать как неотправленное', onSelect: () => askUnsent(row) }]"
|
|
932
|
+
v-on:click="retryFromDropdown($event, row)"
|
|
933
|
+
>
|
|
934
|
+
<template v-slot:button>
|
|
935
|
+
<span class="block px-2 py-1 text-sm text-gray-700">Отправить заново</span>
|
|
936
|
+
</template>
|
|
937
|
+
</dropdown-button-with-action>
|
|
938
|
+
|
|
939
|
+
retryFromDropdown(event, sms) {
|
|
940
|
+
if (event.currentTarget.firstElementChild.contains(event.target)) {
|
|
941
|
+
this.askRetry(sms);
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
|
|
945
|
+
Стало:
|
|
946
|
+
|
|
947
|
+
<dropdown-button-with-action
|
|
948
|
+
:actions="[
|
|
949
|
+
{ label: 'Отправить заново', onSelect: () => askRetry(row) },
|
|
950
|
+
{ label: 'Зафиксировать как неотправленное', onSelect: () => askUnsent(row) },
|
|
951
|
+
]"
|
|
952
|
+
/>
|
|
953
|
+
|
|
954
|
+
`retryFromDropdown` удаляется: он полагался на разметку пакета.
|
|
955
|
+
- Поле `danger` заменено цветом: `danger: true` → `color: 'red'`. Пункт
|
|
956
|
+
с `danger` рисуется обычным, а в режиме разработки в консоль уходит
|
|
957
|
+
предупреждение с заменой. Новый цвет — `color: 'yellow'`. Цвета есть
|
|
958
|
+
и у пунктов `HamburgerMenu`.
|
|
959
|
+
- Красный пункт меню — мягкий: красный текст, при подсветке светлый
|
|
960
|
+
красный фон, а не заливка `red-400` с белым текстом.
|
|
961
|
+
- `0.15.0` не подтянется по `^0.14.0`: для версий `0.x` знак `^` пропускает
|
|
962
|
+
только патчи. Обновление — `npm install @boobooking/dashboard-ui-components@^0.15.0`.
|
|
963
|
+
|
|
788
964
|
## Обновление с 0.13
|
|
789
965
|
|
|
790
966
|
- `DropdownButtonWithAction`: пункты меню передаются пропом `actions`,
|
|
@@ -868,7 +1044,7 @@ Tailwind, `@tailwindcss/forms` и типографикой, как у потре
|
|
|
868
1044
|
`ConfirmationModal`.
|
|
869
1045
|
|
|
870
1046
|
Ресет пакета распространяется и на содержимое слотов — разметку приложения
|
|
871
|
-
внутри `
|
|
1047
|
+
внутри `DropdownButtonWithAction`. Ресет лежит в слое
|
|
872
1048
|
`components`, поэтому внутри слота он сильнее всего, что приложение объявило
|
|
873
1049
|
в слое `base`: preflight, `@tailwindcss/forms` и собственных умолчаний
|
|
874
1050
|
приложения. В слоте он задаёт:
|
|
@@ -892,10 +1068,6 @@ Tailwind, `@tailwindcss/forms` и типографикой, как у потре
|
|
|
892
1068
|
checked:bg-current checked:border-transparent focus:ring-2
|
|
893
1069
|
focus:ring-offset-2`.
|
|
894
1070
|
|
|
895
|
-
У `Closer` нет доступного имени, и он выключен из порядка табуляции
|
|
896
|
-
(`tabindex="-1"`): скринридер его не назовёт, а с клавиатуры до него не
|
|
897
|
-
добраться.
|
|
898
|
-
|
|
899
1071
|
`ConfirmationModal` не переносит фокус внутрь при открытии, не удерживает его
|
|
900
1072
|
внутри, не возвращает на прежнее место после закрытия и не закрывается по
|
|
901
1073
|
Escape.
|