@soxa-ui/theme-base 0.0.0-stage → 0.3.0-beta.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/LICENSE +21 -0
- package/README.md +399 -2
- package/dist/setup/index.d.ts +31 -0
- package/dist/setup/index.js +4 -0
- package/dist/setup/plugins/index.d.ts +3 -0
- package/dist/setup/plugins/table-head.plugin.d.ts +44 -0
- package/dist/setup/plugins/table-head.plugin.js +86 -0
- package/dist/setup/plugins/tabs-view.plugin.d.ts +32 -0
- package/dist/setup/plugins/tabs-view.plugin.js +100 -0
- package/dist/setup/plugins/toasts-front.plugin.d.ts +63 -0
- package/dist/setup/plugins/toasts-front.plugin.js +131 -0
- package/dist/setup/plugins/transitions.d.ts +43 -0
- package/dist/setup/plugins/transitions.js +75 -0
- package/package.json +55 -4
- package/src/anchored.css +75 -0
- package/src/caption.css +71 -0
- package/src/components/accordion.css +96 -0
- package/src/components/button.css +139 -0
- package/src/components/calendar.css +594 -0
- package/src/components/check-box.css +121 -0
- package/src/components/date-input.css +224 -0
- package/src/components/date-picker.css +208 -0
- package/src/components/dialog.css +95 -0
- package/src/components/drag-and-drop.css +18 -0
- package/src/components/drawer.css +171 -0
- package/src/components/field.css +440 -0
- package/src/components/icon.css +61 -0
- package/src/components/input.css +189 -0
- package/src/components/label.css +160 -0
- package/src/components/list-box.css +165 -0
- package/src/components/menu.css +224 -0
- package/src/components/number-input.css +183 -0
- package/src/components/pagination.css +164 -0
- package/src/components/popover.css +164 -0
- package/src/components/progress-linear.css +88 -0
- package/src/components/progress-spinner.css +127 -0
- package/src/components/radio-group.css +130 -0
- package/src/components/rating.css +141 -0
- package/src/components/scroller.css +136 -0
- package/src/components/select.css +233 -0
- package/src/components/skeleton.css +33 -0
- package/src/components/slider.css +482 -0
- package/src/components/switch.css +142 -0
- package/src/components/table.css +1513 -0
- package/src/components/tabs.css +166 -0
- package/src/components/tags.css +371 -0
- package/src/components/textarea.css +179 -0
- package/src/components/toasts.css +447 -0
- package/src/components/tooltip.css +59 -0
- package/src/direction.css +30 -0
- package/src/disabled.css +26 -0
- package/src/group.css +90 -0
- package/src/index.css +97 -0
- package/src/modal.css +183 -0
- package/src/place.css +30 -0
- package/src/required.css +40 -0
- package/src/reset.css +172 -0
- package/src/swipe.css +71 -0
- package/src/target.css +46 -0
- package/theme-contract.json +3373 -0
- package/theme-variables.json +336 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/* ─── Menu ────────────────────────────────────────────────────
|
|
2
|
+
* Меню действий у кнопки (APG Menu Button): триггер потребителя и панель с
|
|
3
|
+
* пунктами. Пункт выполняет действие, флажок и переключатель ещё и
|
|
4
|
+
* отмечаются, пункт с подменю (`Menu.Submenu`) открывает сбоку такую же
|
|
5
|
+
* панель меню, а пункт с панелью (`Menu.PopoverItem`) — свою панель с любым
|
|
6
|
+
* содержимым.
|
|
7
|
+
*
|
|
8
|
+
* .so-menu корень — обёртка триггера и якорь панели
|
|
9
|
+
* .so-menu__panel панель меню и подменю — Frame в `body`
|
|
10
|
+
* .so-menu__list список пунктов — прокручивается он
|
|
11
|
+
* .so-menu-item пункт — строка (Button)
|
|
12
|
+
* .so-menu-item__indicator отметка флажка и переключателя
|
|
13
|
+
* .so-menu-item__dot точка отмеченного переключателя
|
|
14
|
+
* .so-menu-item__icon значок
|
|
15
|
+
* .so-menu-item__shortcut подсказка сочетания клавиш
|
|
16
|
+
* .so-menu-item__arrow стрелка пункта с подменю и с панелью
|
|
17
|
+
* .so-menu-group группа — подпись и её пункты
|
|
18
|
+
* .so-menu-group__label подпись группы (`group.css`)
|
|
19
|
+
* .so-menu-separator разделитель (`group.css`)
|
|
20
|
+
* .so-menu-item__panel панель пункта — Frame в `body`
|
|
21
|
+
* .so-menu-item__content её содержимое — прокручивается оно
|
|
22
|
+
*
|
|
23
|
+
* Корень — строчный флекс, как у Popover: в строке текста он встаёт строчным
|
|
24
|
+
* элементом, во флекс-ряду — обычным элементом ряда, а прямоугольник корня —
|
|
25
|
+
* прямоугольник триггера, и якорю есть что мерить.
|
|
26
|
+
*
|
|
27
|
+
* Ширина панели меню — по самому широкому пункту: список просит ширину
|
|
28
|
+
* содержимого целиком, и от места панели у края окна она не зависит. Минимум и
|
|
29
|
+
* потолок — те же, что у ListBox (`components/list-box.css`): короткое меню
|
|
30
|
+
* не складывается в узкий столбец, а длинный текст пункта режется
|
|
31
|
+
* многоточием. Потолок не шире окна — сдвиг `TAnchorPlugin` держит панель в
|
|
32
|
+
* окне, только пока она в него помещается. Высота — как у Popover: панель
|
|
33
|
+
* встаёт на ту сторону от якоря, где места больше, и длинное меню
|
|
34
|
+
* прокручивается внутри панели, а не уходит за край окна.
|
|
35
|
+
*
|
|
36
|
+
* Список растёт на всю панель, когда минимум панели шире пунктов, и
|
|
37
|
+
* сжимается, когда упирается в её потолок, — тогда текст пунктов режется
|
|
38
|
+
* многоточием. Поле — внутри прокрутки: подсвеченная строка не прижата к
|
|
39
|
+
* кромке. Зазоров между пунктами у списка нет — место между секциями дают поля
|
|
40
|
+
* разделителя.
|
|
41
|
+
*
|
|
42
|
+
* Пункт не сжимается: длинное меню прокручивается, а не сплющивает пункты.
|
|
43
|
+
* Строка — прямой ребёнок пункта, и её правила пишутся ребёнком: кнопка,
|
|
44
|
+
* которую положили в слот строки, тоже `.so-button`. Пункт — не кнопка в
|
|
45
|
+
* форме: курсор обычный, а текст не выделяется протяжкой — меню нажимают,
|
|
46
|
+
* ведут указатель к пункту и отпускают на нём. Содержимое строки — у начала
|
|
47
|
+
* строки.
|
|
48
|
+
*
|
|
49
|
+
* Колонки в начале строки — отметка и значок, каждая в квадрат кегля строки:
|
|
50
|
+
* ширину держит обёртка, а не иконка, и подменённая слотом иконка строку не
|
|
51
|
+
* сдвигает. Колонки держит всё меню, когда они есть хоть у одного пункта, —
|
|
52
|
+
* как меню macOS: тексты пунктов встают одной колонкой. Обёртку отметки
|
|
53
|
+
* рисуют только флажок и переключатель, и пункту без неё место держит пустой
|
|
54
|
+
* первый кусок строки (`::before`) — в ряд частей строки, с её зазором, и в
|
|
55
|
+
* RTL тоже у начала. Обёртка значка есть у каждого пункта, и пустая места не
|
|
56
|
+
* занимает, пока значка нет ни у одного пункта меню. Подсказка сочетания и
|
|
57
|
+
* стрелка — у конца строки, в одну строку, и не сжимаются: длинный текст
|
|
58
|
+
* пункта режется раньше них. Отступ от текста шире зазора частей строки:
|
|
59
|
+
* подсказки и стрелки встают колонкой у края, а не продолжением текста.
|
|
60
|
+
*
|
|
61
|
+
* Разделитель — линия во всю ширину списка поверх его поля, с полями сверху и
|
|
62
|
+
* снизу. Секция без разделителя отступает на его поля и место линии
|
|
63
|
+
* (`group.css`).
|
|
64
|
+
*
|
|
65
|
+
* Панель пункта — немодальный диалог сбоку от строки, а не меню: в ней лежит
|
|
66
|
+
* что угодно. Ширина — по содержимому, без потолка панели меню: календарь в
|
|
67
|
+
* несколько месяцев не должен сжиматься. Потолок — окно без `1rem`, и по
|
|
68
|
+
* высоте тоже: сбоку панель стоит вровень со строкой, и половины окна, как у
|
|
69
|
+
* панелей над и под якорем, ей никто не обещал. Содержимое просит ширину
|
|
70
|
+
* целиком, как у Popover, и прокручивается, а поля — внутри прокрутки, как у
|
|
71
|
+
* содержимого Popover.
|
|
72
|
+
*
|
|
73
|
+
* Поле списка, поля разделителя и подписи, точка переключателя и отступ
|
|
74
|
+
* подсказки — переменные корня документа; умолчания — числа темы oren, тема
|
|
75
|
+
* задаёт свои на корне документа.
|
|
76
|
+
*
|
|
77
|
+
* Облик — поверхность, кромка, тень и скругление панелей, их проявление и
|
|
78
|
+
* исчезание, цвет строк и подсветка пункта, вид строки, цвет подсказки и
|
|
79
|
+
* стрелки, зеркало стрелки в RTL, форма точки — рисует тема. */
|
|
80
|
+
|
|
81
|
+
:root {
|
|
82
|
+
--so-menu-padding: 0.25rem;
|
|
83
|
+
--so-menu-separator-margin: 0.25rem;
|
|
84
|
+
--so-menu-group-label-padding: 0.5rem;
|
|
85
|
+
--so-menu-dot-size: 0.4em;
|
|
86
|
+
--so-menu-shortcut-gap: 1em;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.so-menu {
|
|
90
|
+
display: inline-flex;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.so-menu__panel,
|
|
94
|
+
.so-menu-item__panel {
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.so-menu__panel {
|
|
99
|
+
display: flex;
|
|
100
|
+
min-width: var(--so-list-box-min-width);
|
|
101
|
+
max-width: min(var(--so-list-box-max-width), calc(100vw - 1rem));
|
|
102
|
+
max-height: min(var(--so-popover-max-height), calc(50dvh - 1.5rem));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.so-menu__list {
|
|
106
|
+
display: flex;
|
|
107
|
+
flex-grow: 1;
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
align-self: stretch;
|
|
110
|
+
width: max-content;
|
|
111
|
+
min-width: 0;
|
|
112
|
+
padding: var(--so-menu-padding);
|
|
113
|
+
overflow-y: auto;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.so-menu-item {
|
|
117
|
+
flex-shrink: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.so-menu-item > .so-button {
|
|
121
|
+
cursor: default;
|
|
122
|
+
-webkit-user-select: none;
|
|
123
|
+
user-select: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.so-menu-item > .so-button > .so-button__text {
|
|
127
|
+
min-width: 0;
|
|
128
|
+
text-align: start;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
:where(.so-menu-item > .so-button > .so-button__text > *) {
|
|
132
|
+
margin-inline: 0 auto;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.so-menu-item__indicator,
|
|
136
|
+
.so-menu-item__icon {
|
|
137
|
+
display: inline-flex;
|
|
138
|
+
flex-shrink: 0;
|
|
139
|
+
align-items: center;
|
|
140
|
+
justify-content: center;
|
|
141
|
+
width: 1em;
|
|
142
|
+
height: 1em;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.so-menu-item__icon:empty {
|
|
146
|
+
display: none;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.so-menu-item__dot {
|
|
150
|
+
width: var(--so-menu-dot-size);
|
|
151
|
+
height: var(--so-menu-dot-size);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.so-menu-item__shortcut {
|
|
155
|
+
flex-shrink: 0;
|
|
156
|
+
margin-inline-start: var(--so-menu-shortcut-gap);
|
|
157
|
+
white-space: nowrap;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.so-menu-item__shortcut:empty {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.so-menu-item__arrow {
|
|
165
|
+
display: inline-flex;
|
|
166
|
+
flex-shrink: 0;
|
|
167
|
+
align-items: center;
|
|
168
|
+
justify-content: center;
|
|
169
|
+
width: 1em;
|
|
170
|
+
height: 1em;
|
|
171
|
+
margin-inline-start: var(--so-menu-shortcut-gap);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.so-menu__list:has(.so-menu-item__indicator)
|
|
175
|
+
.so-menu-item:not(:has(> .so-button > .so-menu-item__indicator))
|
|
176
|
+
> .so-button::before {
|
|
177
|
+
content: '';
|
|
178
|
+
flex-shrink: 0;
|
|
179
|
+
width: 1em;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.so-menu__list:has(.so-menu-item__icon:not(:empty)) .so-menu-item__icon:empty {
|
|
183
|
+
display: inline-flex;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.so-menu-group {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-shrink: 0;
|
|
189
|
+
flex-direction: column;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.so-menu-group__label {
|
|
193
|
+
padding-block: var(--so-menu-group-label-padding);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.so-menu-separator {
|
|
197
|
+
margin-block: var(--so-menu-separator-margin);
|
|
198
|
+
margin-inline: calc(-1 * var(--so-menu-padding));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* Секции без разделителя — `groupSeparators` меню или подменю выключен:
|
|
202
|
+
* группа за группой или за пунктом без группы и пункт без группы за группой.
|
|
203
|
+
* Зазоров у списка нет, и без места пункты без группы встали бы вплотную к
|
|
204
|
+
* пунктам последней группы. */
|
|
205
|
+
:is(.so-menu-group, .so-menu-item) + .so-menu-group,
|
|
206
|
+
.so-menu-group + .so-menu-item {
|
|
207
|
+
margin-block-start: calc(
|
|
208
|
+
2 * var(--so-menu-separator-margin) + var(--so-group-separator-width, 0px)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.so-menu-item__panel {
|
|
213
|
+
display: flex;
|
|
214
|
+
max-width: calc(100vw - 1rem);
|
|
215
|
+
max-height: calc(100dvh - 1rem);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.so-menu-item__content {
|
|
219
|
+
width: max-content;
|
|
220
|
+
min-width: 0;
|
|
221
|
+
padding: var(--so-popover-padding);
|
|
222
|
+
overflow-y: auto;
|
|
223
|
+
overflow-wrap: break-word;
|
|
224
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/* ─── NumberInput ─────────────────────────────────────────────
|
|
2
|
+
* Поле числа семьи Input: ввод и кнопки шага «меньше» и «больше».
|
|
3
|
+
*
|
|
4
|
+
* .so-number-input корень — коробка поля
|
|
5
|
+
* .so-number-input__leading слот перед числом
|
|
6
|
+
* .so-number-input__input ввод — число строкой Intl
|
|
7
|
+
* .so-number-input__trailing слот после числа
|
|
8
|
+
* .so-number-input__clear кнопка очистки, первой в слоте — Button
|
|
9
|
+
* .so-number-input__stepper кнопки шага — у конца поля
|
|
10
|
+
* .so-number-input__decrement «меньше» — Button
|
|
11
|
+
* .so-number-input__increment «больше» — Button
|
|
12
|
+
*
|
|
13
|
+
* Коробка — та же, что у Input (`input.css`): высота размера, строка слота,
|
|
14
|
+
* слоты у краёв логическими сторонами. Шкала — шкала поля: высота, кегль и
|
|
15
|
+
* отступ числа от рамки те же, что у Input того же размера, и NumberInput
|
|
16
|
+
* стоит вровень с ним в одной форме. Ширина — минимум Input, а не по
|
|
17
|
+
* содержимому: длина числа заранее не известна, и поле без минимума
|
|
18
|
+
* схлопнулось бы до кнопок.
|
|
19
|
+
*
|
|
20
|
+
* Рамку рисует тема и задаёт её толщину на блоке
|
|
21
|
+
* (`--so-number-input-border`, контракт): строка слота считается без неё.
|
|
22
|
+
*
|
|
23
|
+
* Облик — рамка, поверхность, скругление, кольцо фокуса, подсказка пустого
|
|
24
|
+
* поля, цифры одной ширины, вид кнопок и их удержания, цвет точки
|
|
25
|
+
* обязательного поля, варианты и ошибка — рисует тема. */
|
|
26
|
+
|
|
27
|
+
/* Размер без модификатора — `normal`: ядро пишет `--size-*` всегда, но блок
|
|
28
|
+
* и без него обязан выглядеть умолчанием. `relative` — опора точки
|
|
29
|
+
* обязательного поля (`required.css`). */
|
|
30
|
+
.so-number-input {
|
|
31
|
+
--so-number-input-height: var(--so-input-height-normal);
|
|
32
|
+
--so-number-input-slot-row: calc(
|
|
33
|
+
var(--so-number-input-height) - 2 * var(--so-number-input-border, 0px) - 2 *
|
|
34
|
+
var(--so-input-slot-gap)
|
|
35
|
+
);
|
|
36
|
+
position: relative;
|
|
37
|
+
display: inline-flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
height: var(--so-number-input-height);
|
|
40
|
+
min-width: var(--so-input-min-width);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Выключенное поле гаснет коробкой целиком, с кнопками и содержимым слотов
|
|
44
|
+
* (`disabled.css`). Выключенность корень несёт сам (`data-disabled`): искать
|
|
45
|
+
* её у вложенного ввода незачем, а `:disabled` у корня-`div` не срабатывает. */
|
|
46
|
+
.so-number-input[data-disabled='true'] {
|
|
47
|
+
opacity: var(--so-disabled-opacity);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.so-number-input[data-disabled='true'] > * {
|
|
51
|
+
--so-disabled-opacity: 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Отступ числа — полями поровну с обеих сторон, а не `text-indent`, как у
|
|
55
|
+
* Input: отступ строки стоит у начала по направлению самого ввода, а число
|
|
56
|
+
* стоит у начала поля (ниже). Когда направления разные — число справа налево
|
|
57
|
+
* в поле слева направо, — отступ ушёл бы к другому краю, и число легло бы
|
|
58
|
+
* вплотную к рамке. У начала поля текст стоит там же, где у Input. Строка
|
|
59
|
+
* ввода — во всю высоту поля. Кегль — вводу, а не корню: слоты — разметка
|
|
60
|
+
* потребителя. */
|
|
61
|
+
.so-number-input > .so-number-input__input {
|
|
62
|
+
padding-inline: var(--so-input-indent-normal);
|
|
63
|
+
line-height: var(--so-number-input-height);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Число — у начала поля, как текст Input: в форме поля стоят столбцом, и
|
|
67
|
+
* значение каждого начинается там же, где у соседей.
|
|
68
|
+
*
|
|
69
|
+
* Начало — поля, а не самого ввода (`match-parent`). У числа своё
|
|
70
|
+
* направление письма: строку Intl `ar-EG`, `he-IL` и `fa-IR` пишут справа
|
|
71
|
+
* налево, `ru-RU` — слева направо на любой странице, и порядок знака, валюты и
|
|
72
|
+
* единицы в ней верен, только когда направление ввода — направление числа.
|
|
73
|
+
* Со `start` такой ввод ставил бы число к концу поля, когда направления числа
|
|
74
|
+
* и поля разные. Без своего `dir` у ввода `match-parent` — то же `start`.
|
|
75
|
+
* Chromium понимает только `-webkit-match-parent`, Firefox — стандартное
|
|
76
|
+
* `match-parent`: браузер оставляет объявление, которое понял, а понявший
|
|
77
|
+
* оба — последнее, стандартное. */
|
|
78
|
+
.so-number-input__input {
|
|
79
|
+
width: 100%;
|
|
80
|
+
min-width: var(--so-input-text-min-width);
|
|
81
|
+
text-align: -webkit-match-parent;
|
|
82
|
+
text-align: match-parent;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.so-number-input[data-disabled='true'] > .so-number-input__input {
|
|
86
|
+
cursor: default;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Слоты и кнопки шага — строкой поля, со сторонами по направлению поля, как
|
|
90
|
+
* у Input. Не сжимаются: в узком поле уступает ввод, а не кнопки. */
|
|
91
|
+
.so-number-input__leading,
|
|
92
|
+
.so-number-input__trailing,
|
|
93
|
+
.so-number-input__stepper {
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-shrink: 0;
|
|
96
|
+
align-items: center;
|
|
97
|
+
justify-content: center;
|
|
98
|
+
gap: var(--so-input-slot-spacing);
|
|
99
|
+
height: var(--so-number-input-slot-row);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.so-number-input__leading {
|
|
103
|
+
padding-inline-start: var(--so-input-slot-padding);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.so-number-input__trailing {
|
|
107
|
+
padding-inline-end: var(--so-input-slot-padding);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Кнопки шага — одна пара, а не ещё две кнопки в ряду со слотом: от очистки
|
|
111
|
+
* и содержимого `trailing` их отделяет двойной зазор — поле слота у его конца
|
|
112
|
+
* и своё у начала. Ровным шагом «× − +» читались бы тремя равными
|
|
113
|
+
* действиями, а очистка относится к числу, а не к шагу. У конца поля поле
|
|
114
|
+
* то же, что у слота. В RTL ряд зеркален сам — флекс поля идёт по его
|
|
115
|
+
* направлению, — и «больше» стоит у левого края. */
|
|
116
|
+
.so-number-input__stepper {
|
|
117
|
+
padding-inline: var(--so-input-slot-padding);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Кнопки — квадраты в строку слота, как очистка Input: рядом, а не столбцом
|
|
121
|
+
* по половине строки, как стрелки нативного поля, — половина строки не дала
|
|
122
|
+
* бы цели ни на одном размере. Цель на мелком размере добирает зона нажатия
|
|
123
|
+
* (`target.css`); зоны пары сходятся встык, а до очистки и ввода не достают:
|
|
124
|
+
* от них пару отделяет её поле. */
|
|
125
|
+
.so-number-input__clear,
|
|
126
|
+
.so-number-input__decrement,
|
|
127
|
+
.so-number-input__increment {
|
|
128
|
+
flex-shrink: 0;
|
|
129
|
+
padding-inline: 0;
|
|
130
|
+
inline-size: var(--so-number-input-slot-row);
|
|
131
|
+
block-size: var(--so-number-input-slot-row);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Шаг повторяют касаниями подряд: двойное касание не увеличивает страницу, а
|
|
135
|
+
* шагает дважды. */
|
|
136
|
+
.so-number-input__decrement,
|
|
137
|
+
.so-number-input__increment {
|
|
138
|
+
touch-action: manipulation;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.so-number-input--size-sm {
|
|
142
|
+
--so-number-input-height: var(--so-input-height-sm);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.so-number-input--size-sm > .so-number-input__input {
|
|
146
|
+
font-size: var(--so-input-font-size-sm);
|
|
147
|
+
padding-inline: var(--so-input-indent-sm);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.so-number-input--size-normal {
|
|
151
|
+
--so-number-input-height: var(--so-input-height-normal);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.so-number-input--size-normal > .so-number-input__input {
|
|
155
|
+
padding-inline: var(--so-input-indent-normal);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.so-number-input--size-lg {
|
|
159
|
+
--so-number-input-height: var(--so-input-height-lg);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.so-number-input--size-lg > .so-number-input__input {
|
|
163
|
+
font-size: var(--so-input-font-size-lg);
|
|
164
|
+
padding-inline: var(--so-input-indent-lg);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.so-number-input--size-xl {
|
|
168
|
+
--so-number-input-height: var(--so-input-height-xl);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.so-number-input--size-xl > .so-number-input__input {
|
|
172
|
+
font-size: var(--so-input-font-size-xl);
|
|
173
|
+
padding-inline: var(--so-input-indent-xl);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.so-number-input--size-2xl {
|
|
177
|
+
--so-number-input-height: var(--so-input-height-2xl);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.so-number-input--size-2xl > .so-number-input__input {
|
|
181
|
+
font-size: var(--so-input-font-size-2xl);
|
|
182
|
+
padding-inline: var(--so-input-indent-2xl);
|
|
183
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/* ─── Pagination ──────────────────────────────────────────────
|
|
2
|
+
* Page navigation: arrows at the edges and between them the list of pages
|
|
3
|
+
* with gaps. The first and the last page are always shown, between them N
|
|
4
|
+
* pages around the current one, and an ellipsis in place of the skipped ones:
|
|
5
|
+
* `‹ 1 … 4 5 6 … 10 ›`.
|
|
6
|
+
*
|
|
7
|
+
* .so-pagination root — `nav`, a row in one line
|
|
8
|
+
* .so-pagination__prev the "back" arrow (Button)
|
|
9
|
+
* .so-pagination__list the list — `ol`: pages and gaps in order
|
|
10
|
+
* .so-pagination-item a page — `li`, an item of the collection
|
|
11
|
+
* .so-button the row of a page: number or text (Button)
|
|
12
|
+
* .so-pagination__ellipsis a gap — `li` with "…", markup of the owner
|
|
13
|
+
* .so-pagination__next the "forward" arrow (Button)
|
|
14
|
+
*
|
|
15
|
+
* One line without wrapping, as wide as its content: a container cannot
|
|
16
|
+
* squeeze the row — the row of a page would be cut by an ellipsis and its
|
|
17
|
+
* number would vanish. Centring the row or putting it at the end is up to the
|
|
18
|
+
* place. Digits of one width: "11" is not narrower than "18", and the row does
|
|
19
|
+
* not jump while paging. Cells do not shrink.
|
|
20
|
+
*
|
|
21
|
+
* The scale is that of Button (`components/button.css`): the side of a cell is
|
|
22
|
+
* its height, the gap between cells the gap between the parts of its row, the
|
|
23
|
+
* font its font. Pages and arrows are Buttons of this size and take the font
|
|
24
|
+
* themselves; the gap cell has to match them and takes the same step on its
|
|
25
|
+
* own node. Not on the root: a step counts from the font of the parent, and
|
|
26
|
+
* the Buttons inside would count theirs from the root's and grow a second
|
|
27
|
+
* step. At `normal` there is no font of its own, as with Button. The block
|
|
28
|
+
* takes the steps of its size into `--so-pagination-cell` and
|
|
29
|
+
* `--so-pagination-gap`.
|
|
30
|
+
*
|
|
31
|
+
* The row of a page is not narrower than a cell and as tall as one: a narrow
|
|
32
|
+
* number stands as a square, while a wider number and text widen the row by
|
|
33
|
+
* their field. The field is what remains of the cell after two digits (`ch`
|
|
34
|
+
* is the width of a digit: digits of one width), equally on each side: one-
|
|
35
|
+
* and two-digit numbers stand as squares, and the row keeps its width from 9
|
|
36
|
+
* to 10. The field of Button is too large for that. Arrows are the square of a
|
|
37
|
+
* cell: the button holds one icon, and the field is removed. Rows and arrows
|
|
38
|
+
* override the scale of Button with the same or a higher specificity, so this
|
|
39
|
+
* file is imported below `button.css`.
|
|
40
|
+
*
|
|
41
|
+
* The current page is `data-selected` on the wrapper of the page: a click on
|
|
42
|
+
* it changes nothing, and the cursor is the default. A gap is a cell as wide
|
|
43
|
+
* as a narrow page, on which nothing is pressed. A disabled component fades as
|
|
44
|
+
* a whole at its root (`disabled.css`); pages and arrows are disabled with it
|
|
45
|
+
* and do not fade a second time under the faded root.
|
|
46
|
+
*
|
|
47
|
+
* The look — the view of pages and arrows, the mark of the current one, the
|
|
48
|
+
* colour of a gap, transitions, the mirror of arrows in RTL and the view in
|
|
49
|
+
* forced colours mode — is drawn by the theme. */
|
|
50
|
+
|
|
51
|
+
/* Размер без модификатора — `normal`: ядро пишет `--size-*` всегда, но блок и
|
|
52
|
+
* без него обязан выглядеть умолчанием. */
|
|
53
|
+
.so-pagination {
|
|
54
|
+
--so-pagination-cell: var(--so-button-height-normal);
|
|
55
|
+
--so-pagination-gap: var(--so-button-gap-normal);
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: var(--so-pagination-gap);
|
|
59
|
+
width: max-content;
|
|
60
|
+
font-variant-numeric: tabular-nums;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.so-pagination--size-sm {
|
|
64
|
+
--so-pagination-cell: var(--so-button-height-sm);
|
|
65
|
+
--so-pagination-gap: var(--so-button-gap-sm);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.so-pagination--size-sm > .so-pagination__list > .so-pagination__ellipsis {
|
|
69
|
+
font-size: var(--so-button-font-size-sm);
|
|
70
|
+
line-height: var(--so-button-line-height-sm);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.so-pagination--size-normal {
|
|
74
|
+
--so-pagination-cell: var(--so-button-height-normal);
|
|
75
|
+
--so-pagination-gap: var(--so-button-gap-normal);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.so-pagination--size-lg {
|
|
79
|
+
--so-pagination-cell: var(--so-button-height-lg);
|
|
80
|
+
--so-pagination-gap: var(--so-button-gap-lg);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.so-pagination--size-lg > .so-pagination__list > .so-pagination__ellipsis {
|
|
84
|
+
font-size: var(--so-button-font-size-lg);
|
|
85
|
+
line-height: var(--so-button-line-height-lg);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.so-pagination--size-xl {
|
|
89
|
+
--so-pagination-cell: var(--so-button-height-xl);
|
|
90
|
+
--so-pagination-gap: var(--so-button-gap-xl);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.so-pagination--size-xl > .so-pagination__list > .so-pagination__ellipsis {
|
|
94
|
+
font-size: var(--so-button-font-size-xl);
|
|
95
|
+
line-height: var(--so-button-line-height-xl);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.so-pagination--size-2xl {
|
|
99
|
+
--so-pagination-cell: var(--so-button-height-2xl);
|
|
100
|
+
--so-pagination-gap: var(--so-button-gap-2xl);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.so-pagination--size-2xl > .so-pagination__list > .so-pagination__ellipsis {
|
|
104
|
+
font-size: var(--so-button-font-size-2xl);
|
|
105
|
+
line-height: var(--so-button-line-height-2xl);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Список — тот же ряд: страницы и пропуски через тот же зазор, что между
|
|
109
|
+
* стрелкой и списком. */
|
|
110
|
+
.so-pagination__list {
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: var(--so-pagination-gap);
|
|
114
|
+
margin: 0;
|
|
115
|
+
padding: 0;
|
|
116
|
+
list-style-type: none;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.so-pagination-item {
|
|
120
|
+
display: flex;
|
|
121
|
+
flex-shrink: 0;
|
|
122
|
+
margin: 0;
|
|
123
|
+
padding: 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.so-pagination-item > .so-button {
|
|
127
|
+
min-inline-size: var(--so-pagination-cell);
|
|
128
|
+
block-size: var(--so-pagination-cell);
|
|
129
|
+
padding-inline: max(0px, (var(--so-pagination-cell) - 2ch) / 2);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.so-pagination__prev,
|
|
133
|
+
.so-pagination__next {
|
|
134
|
+
flex-shrink: 0;
|
|
135
|
+
inline-size: var(--so-pagination-cell);
|
|
136
|
+
block-size: var(--so-pagination-cell);
|
|
137
|
+
padding-inline: 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.so-pagination-item[data-selected='true'] > .so-button {
|
|
141
|
+
cursor: default;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.so-pagination__ellipsis {
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-shrink: 0;
|
|
147
|
+
align-items: center;
|
|
148
|
+
justify-content: center;
|
|
149
|
+
inline-size: var(--so-pagination-cell);
|
|
150
|
+
block-size: var(--so-pagination-cell);
|
|
151
|
+
margin: 0;
|
|
152
|
+
padding: 0;
|
|
153
|
+
cursor: default;
|
|
154
|
+
-webkit-user-select: none;
|
|
155
|
+
user-select: none;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.so-pagination[data-disabled='true'] {
|
|
159
|
+
opacity: var(--so-disabled-opacity);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.so-pagination[data-disabled='true'] > * {
|
|
163
|
+
--so-disabled-opacity: 1;
|
|
164
|
+
}
|