vanilla-jui 1.4.7 → 1.5.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 +10 -4
- package/dist/index.d.ts +418 -970
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -3
- package/src/components/accordion.ts +466 -346
- package/src/components/flow.ts +779 -1133
- package/src/components/form.ts +666 -509
- package/src/components/menu.ts +198 -328
- package/src/components/modal.ts +510 -747
- package/src/components/offcanvas.ts +273 -367
- package/src/components/pagination.ts +201 -375
- package/src/components/swiper.ts +689 -1107
- package/src/components/tabs.ts +467 -778
- package/src/components/toc.ts +191 -244
- package/src/core/component.ts +332 -0
- package/src/core/motion.ts +298 -0
- package/src/core/presence.ts +233 -0
- package/src/core/scheduler.ts +91 -0
- package/src/core/view.ts +31 -0
- package/src/css/accordion.css +94 -3
- package/src/css/content.css +18 -24
- package/src/css/drop.css +4 -1
- package/src/css/form.css +8 -0
- package/src/css/menu.css +10 -5
- package/src/css/modal.css +2 -1
- package/src/css/offcanvas.css +5 -17
- package/src/css/swiper.css +2 -1
- package/src/css/tabs.css +8 -17
- package/src/css/themes/default/accordion.css +0 -48
- package/src/css/themes/default/swiper.css +1 -1
- package/src/css/themes/default/tabs.css +4 -6
- package/src/css/toast.css +1 -17
- package/src/css/tooltip.css +2 -1
- package/src/index.ts +8 -2
- package/src/locales/index.ts +3 -0
- package/src/primitives/drop.ts +253 -262
- package/src/primitives/loading.ts +22 -4
- package/src/primitives/parabola.ts +123 -164
- package/src/primitives/sticky.ts +297 -0
- package/src/primitives/theme.ts +164 -222
- package/src/primitives/toast.ts +309 -284
- package/src/primitives/tooltip.ts +65 -66
- package/src/utilities/browser.ts +38 -0
- package/src/utilities/dom.ts +0 -54
- package/src/utilities/refs.ts +61 -0
- package/src/utilities/state.ts +73 -0
- package/src/utilities/timer.ts +11 -31
- package/src/validation/validator.ts +289 -389
- package/src/components/sticky.ts +0 -297
- package/src/core/Component.ts +0 -377
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { flushSync } from 'vanilla-signal';
|
|
2
|
+
|
|
3
|
+
import { type MotionController } from './motion.ts';
|
|
4
|
+
|
|
5
|
+
export type PresencePhase = 'hidden' | 'entering' | 'visible' | 'leaving';
|
|
6
|
+
|
|
7
|
+
export interface PresenceOptions {
|
|
8
|
+
elements: () => readonly (Element | null | undefined)[];
|
|
9
|
+
mount: () => void;
|
|
10
|
+
activate: () => void;
|
|
11
|
+
deactivate: () => void;
|
|
12
|
+
unmount: () => void;
|
|
13
|
+
motion?: MotionController;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface PresenceController {
|
|
17
|
+
readonly phase: PresencePhase;
|
|
18
|
+
enter: () => Promise<boolean>;
|
|
19
|
+
leave: () => Promise<boolean>;
|
|
20
|
+
cancel: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function connectedElements(
|
|
24
|
+
values: readonly (Element | null | undefined)[]
|
|
25
|
+
): Element[] {
|
|
26
|
+
return values.filter(
|
|
27
|
+
(value): value is Element => value != null && value.isConnected
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function commitInitialStyles(elements: readonly Element[]): void {
|
|
32
|
+
elements[0]?.getBoundingClientRect();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function timeList(value: string): number[] {
|
|
36
|
+
return value.split(',').map((part) => {
|
|
37
|
+
const time = part.trim();
|
|
38
|
+
if (time.endsWith('ms')) return Number.parseFloat(time) || 0;
|
|
39
|
+
if (time.endsWith('s')) return (Number.parseFloat(time) || 0) * 1000;
|
|
40
|
+
return 0;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function numberList(value: string): number[] {
|
|
45
|
+
return value.split(',').map((part) => {
|
|
46
|
+
const count = Number.parseFloat(part);
|
|
47
|
+
return Number.isFinite(count) ? count : 0;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function timelineDuration(
|
|
52
|
+
durations: number[],
|
|
53
|
+
delays: number[],
|
|
54
|
+
iterations: number[] = [1],
|
|
55
|
+
enabled: boolean[] = [true]
|
|
56
|
+
): number {
|
|
57
|
+
const count = Math.max(
|
|
58
|
+
durations.length,
|
|
59
|
+
delays.length,
|
|
60
|
+
iterations.length,
|
|
61
|
+
enabled.length
|
|
62
|
+
);
|
|
63
|
+
let duration = 0;
|
|
64
|
+
for (let index = 0; index < count; index += 1) {
|
|
65
|
+
if (!enabled[index % enabled.length]) continue;
|
|
66
|
+
const active =
|
|
67
|
+
(durations[index % durations.length] || 0) *
|
|
68
|
+
(iterations[index % iterations.length] || 0) +
|
|
69
|
+
(delays[index % delays.length] || 0);
|
|
70
|
+
duration = Math.max(duration, active);
|
|
71
|
+
}
|
|
72
|
+
return Math.max(0, duration);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function computedMotionDuration(element: Element): number {
|
|
76
|
+
const view = element.ownerDocument.defaultView;
|
|
77
|
+
if (!view) return 0;
|
|
78
|
+
const style = view.getComputedStyle(element);
|
|
79
|
+
const transition = timelineDuration(
|
|
80
|
+
timeList(style.transitionDuration),
|
|
81
|
+
timeList(style.transitionDelay),
|
|
82
|
+
[1],
|
|
83
|
+
style.transitionProperty
|
|
84
|
+
.split(',')
|
|
85
|
+
.map((property) => property.trim() !== 'none')
|
|
86
|
+
);
|
|
87
|
+
const animation = timelineDuration(
|
|
88
|
+
timeList(style.animationDuration),
|
|
89
|
+
timeList(style.animationDelay),
|
|
90
|
+
numberList(style.animationIterationCount),
|
|
91
|
+
style.animationName.split(',').map((name) => name.trim() !== 'none')
|
|
92
|
+
);
|
|
93
|
+
return Math.max(transition, animation);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function waitForDuration(
|
|
97
|
+
duration: number,
|
|
98
|
+
signal?: AbortSignal
|
|
99
|
+
): Promise<void> {
|
|
100
|
+
return new Promise((resolve) => {
|
|
101
|
+
if (signal?.aborted) {
|
|
102
|
+
resolve();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const finish = (): void => {
|
|
106
|
+
clearTimeout(timeout);
|
|
107
|
+
signal?.removeEventListener('abort', finish);
|
|
108
|
+
resolve();
|
|
109
|
+
};
|
|
110
|
+
const timeout = setTimeout(finish, duration);
|
|
111
|
+
signal?.addEventListener('abort', finish, { once: true });
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function waitForMotion(
|
|
116
|
+
elements: readonly Element[],
|
|
117
|
+
signal?: AbortSignal
|
|
118
|
+
): Promise<void> {
|
|
119
|
+
const animations = new Set<Animation>();
|
|
120
|
+
let fallbackDuration = 0;
|
|
121
|
+
for (const element of elements) {
|
|
122
|
+
if (typeof element.getAnimations !== 'function') {
|
|
123
|
+
fallbackDuration = Math.max(
|
|
124
|
+
fallbackDuration,
|
|
125
|
+
computedMotionDuration(element)
|
|
126
|
+
);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
for (const animation of element.getAnimations()) {
|
|
130
|
+
const endTime = animation.effect?.getComputedTiming().endTime;
|
|
131
|
+
if (typeof endTime !== 'number' || Number.isFinite(endTime)) {
|
|
132
|
+
animations.add(animation);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const pending = Array.from(
|
|
137
|
+
animations,
|
|
138
|
+
(animation) => animation.finished as Promise<unknown>
|
|
139
|
+
);
|
|
140
|
+
if (fallbackDuration > 0) {
|
|
141
|
+
pending.push(waitForDuration(fallbackDuration, signal));
|
|
142
|
+
}
|
|
143
|
+
if (pending.length === 0) return;
|
|
144
|
+
const settled = Promise.allSettled(pending);
|
|
145
|
+
if (!signal) {
|
|
146
|
+
await settled;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
await new Promise<void>((resolve) => {
|
|
150
|
+
const finish = (): void => {
|
|
151
|
+
signal.removeEventListener('abort', finish);
|
|
152
|
+
resolve();
|
|
153
|
+
};
|
|
154
|
+
if (signal.aborted) {
|
|
155
|
+
finish();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
signal.addEventListener('abort', finish, { once: true });
|
|
159
|
+
void settled.then(finish);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function createPresence(options: PresenceOptions): PresenceController {
|
|
164
|
+
let phase: PresencePhase = 'hidden';
|
|
165
|
+
let operation = 0;
|
|
166
|
+
let entering: Promise<boolean> | null = null;
|
|
167
|
+
let leaving: Promise<boolean> | null = null;
|
|
168
|
+
let motionController: AbortController | null = null;
|
|
169
|
+
|
|
170
|
+
const nextMotion = (): AbortSignal => {
|
|
171
|
+
motionController?.abort();
|
|
172
|
+
motionController = new AbortController();
|
|
173
|
+
return motionController.signal;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const enter = (): Promise<boolean> => {
|
|
177
|
+
if (phase === 'visible') return Promise.resolve(false);
|
|
178
|
+
if (phase === 'entering' && entering) return entering;
|
|
179
|
+
|
|
180
|
+
const currentOperation = ++operation;
|
|
181
|
+
const signal = nextMotion();
|
|
182
|
+
phase = 'entering';
|
|
183
|
+
entering = (async () => {
|
|
184
|
+
options.mount();
|
|
185
|
+
const elements = connectedElements(options.elements());
|
|
186
|
+
commitInitialStyles(elements);
|
|
187
|
+
flushSync(options.activate);
|
|
188
|
+
if (options.motion) await options.motion.enter(signal);
|
|
189
|
+
else await waitForMotion(elements, signal);
|
|
190
|
+
if (currentOperation !== operation) return false;
|
|
191
|
+
phase = 'visible';
|
|
192
|
+
return true;
|
|
193
|
+
})();
|
|
194
|
+
return entering;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const leave = (): Promise<boolean> => {
|
|
198
|
+
if (phase === 'hidden') return Promise.resolve(false);
|
|
199
|
+
if (phase === 'leaving' && leaving) return leaving;
|
|
200
|
+
|
|
201
|
+
const currentOperation = ++operation;
|
|
202
|
+
const signal = nextMotion();
|
|
203
|
+
phase = 'leaving';
|
|
204
|
+
leaving = (async () => {
|
|
205
|
+
flushSync(options.deactivate);
|
|
206
|
+
const elements = connectedElements(options.elements());
|
|
207
|
+
if (options.motion) await options.motion.leave(signal);
|
|
208
|
+
else await waitForMotion(elements, signal);
|
|
209
|
+
if (currentOperation !== operation) return false;
|
|
210
|
+
options.unmount();
|
|
211
|
+
phase = 'hidden';
|
|
212
|
+
return true;
|
|
213
|
+
})();
|
|
214
|
+
return leaving;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
get phase() {
|
|
219
|
+
return phase;
|
|
220
|
+
},
|
|
221
|
+
enter,
|
|
222
|
+
leave,
|
|
223
|
+
cancel() {
|
|
224
|
+
operation += 1;
|
|
225
|
+
motionController?.abort();
|
|
226
|
+
motionController = null;
|
|
227
|
+
options.motion?.cancel();
|
|
228
|
+
phase = 'hidden';
|
|
229
|
+
entering = null;
|
|
230
|
+
leaving = null;
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
interface QueueNode {
|
|
2
|
+
queued: boolean;
|
|
3
|
+
enqueued: boolean;
|
|
4
|
+
disposed: boolean;
|
|
5
|
+
next: QueueNode | null;
|
|
6
|
+
run: () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ScheduledTask {
|
|
10
|
+
schedule: () => void;
|
|
11
|
+
flush: () => void;
|
|
12
|
+
cancel: () => void;
|
|
13
|
+
dispose: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let head: QueueNode | null = null;
|
|
17
|
+
let tail: QueueNode | null = null;
|
|
18
|
+
let pending = false;
|
|
19
|
+
|
|
20
|
+
function queueTask(callback: () => void): void {
|
|
21
|
+
if (typeof queueMicrotask === 'function') {
|
|
22
|
+
queueMicrotask(callback);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
void Promise.resolve().then(callback);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function requestFlush(): void {
|
|
29
|
+
if (pending) return;
|
|
30
|
+
pending = true;
|
|
31
|
+
queueTask(flushQueue);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function enqueue(node: QueueNode): void {
|
|
35
|
+
node.enqueued = true;
|
|
36
|
+
if (tail) tail.next = node;
|
|
37
|
+
else head = node;
|
|
38
|
+
tail = node;
|
|
39
|
+
requestFlush();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function flushQueue(): void {
|
|
43
|
+
pending = false;
|
|
44
|
+
const start = head;
|
|
45
|
+
head = null;
|
|
46
|
+
tail = null;
|
|
47
|
+
|
|
48
|
+
let node = start;
|
|
49
|
+
while (node) {
|
|
50
|
+
const next = node.next;
|
|
51
|
+
node.next = null;
|
|
52
|
+
node.enqueued = false;
|
|
53
|
+
|
|
54
|
+
if (!node.disposed && node.queued) {
|
|
55
|
+
node.queued = false;
|
|
56
|
+
node.run();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
node = next;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function createScheduledTask(run: () => void): ScheduledTask {
|
|
64
|
+
const node: QueueNode = {
|
|
65
|
+
queued: false,
|
|
66
|
+
enqueued: false,
|
|
67
|
+
disposed: false,
|
|
68
|
+
next: null,
|
|
69
|
+
run,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
schedule() {
|
|
74
|
+
if (node.disposed || node.queued) return;
|
|
75
|
+
node.queued = true;
|
|
76
|
+
if (!node.enqueued) enqueue(node);
|
|
77
|
+
},
|
|
78
|
+
flush() {
|
|
79
|
+
if (node.disposed) return;
|
|
80
|
+
node.queued = false;
|
|
81
|
+
node.run();
|
|
82
|
+
},
|
|
83
|
+
cancel() {
|
|
84
|
+
node.queued = false;
|
|
85
|
+
},
|
|
86
|
+
dispose() {
|
|
87
|
+
node.disposed = true;
|
|
88
|
+
node.queued = false;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
package/src/core/view.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createRoot, onCleanup, untrack } from 'vanilla-signal';
|
|
2
|
+
|
|
3
|
+
export interface OwnedView<TElement extends Element> {
|
|
4
|
+
element: TElement;
|
|
5
|
+
dispose: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface OwnedViewOptions {
|
|
9
|
+
removeOnDispose?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates one stable view inside a vanilla-signal owner.
|
|
14
|
+
* Reactive accessors declared by the factory retain the owner, while the
|
|
15
|
+
* factory itself is not turned into a replaceable dynamic region.
|
|
16
|
+
*/
|
|
17
|
+
export function createOwnedView<TElement extends Element>(
|
|
18
|
+
factory: () => TElement,
|
|
19
|
+
options: OwnedViewOptions = {}
|
|
20
|
+
): OwnedView<TElement> {
|
|
21
|
+
let element!: TElement;
|
|
22
|
+
const removeOnDispose = options.removeOnDispose !== false;
|
|
23
|
+
|
|
24
|
+
const dispose = createRoot((disposeRoot) => {
|
|
25
|
+
element = untrack(factory);
|
|
26
|
+
if (removeOnDispose) onCleanup(() => element.remove());
|
|
27
|
+
return disposeRoot;
|
|
28
|
+
}) as () => void;
|
|
29
|
+
|
|
30
|
+
return { element, dispose };
|
|
31
|
+
}
|
package/src/css/accordion.css
CHANGED
|
@@ -1,9 +1,51 @@
|
|
|
1
1
|
@layer components {
|
|
2
|
+
.j-accordion {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.j-accordion[data-direction='horizontal'] {
|
|
8
|
+
flex-direction: row;
|
|
9
|
+
}
|
|
10
|
+
|
|
2
11
|
.j-accordion .accordion-header {
|
|
3
12
|
display: flex;
|
|
4
13
|
align-items: center;
|
|
5
14
|
cursor: pointer;
|
|
6
15
|
user-select: none;
|
|
16
|
+
|
|
17
|
+
padding: var(--accordion-header-padding);
|
|
18
|
+
margin: var(--accordion-header-margin);
|
|
19
|
+
font-weight: var(--accordion-font-weight);
|
|
20
|
+
font-size: var(--accordion-header-font-size);
|
|
21
|
+
background: var(--accordion-bg);
|
|
22
|
+
border-bottom: var(--accordion-border);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.j-accordion[data-direction='horizontal'] .accordion-header {
|
|
26
|
+
gap: var(--space);
|
|
27
|
+
border-bottom: 0;
|
|
28
|
+
border-right: var(--accordion-border);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.j-accordion .accordion-header[aria-expanded='true'] {
|
|
32
|
+
border-bottom: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.j-accordion[data-direction='horizontal'] .accordion-header[aria-expanded='true'] {
|
|
36
|
+
border-right: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.j-accordion .accordion-header[aria-expanded='false']:hover {
|
|
40
|
+
--accordion-bg: var(--ui-surface-hover);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.j-accordion .accordion-header[aria-expanded='false']:nth-last-child(2) {
|
|
44
|
+
border-bottom: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.j-accordion[data-direction='horizontal'] .accordion-header[aria-expanded='false']:nth-last-child(2) {
|
|
48
|
+
border-right: 0;
|
|
7
49
|
}
|
|
8
50
|
|
|
9
51
|
.j-accordion .accordion-header .header-title {
|
|
@@ -11,17 +53,66 @@
|
|
|
11
53
|
text-align: left;
|
|
12
54
|
}
|
|
13
55
|
|
|
56
|
+
.j-accordion .accordion-header[aria-expanded='true'] .header-title {
|
|
57
|
+
--accordion-font-weight: var(--font-bold);
|
|
58
|
+
}
|
|
59
|
+
|
|
14
60
|
.j-accordion .accordion-header .header-arrow {
|
|
15
61
|
display: flex;
|
|
16
62
|
justify-content: center;
|
|
17
63
|
align-items: center;
|
|
64
|
+
transition: transform 0.3s ease-out;
|
|
65
|
+
transform: var(--accordion-icon-transform);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.j-accordion[data-direction='horizontal'] .accordion-header .header-arrow {
|
|
69
|
+
--accordion-icon-transform: rotate(-90deg);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.j-accordion .accordion-header[aria-expanded='true'] .header-arrow {
|
|
73
|
+
--accordion-icon-transform: rotate(180deg);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.j-accordion[data-direction='horizontal'] .accordion-header[aria-expanded='true'] .header-arrow {
|
|
77
|
+
--accordion-icon-transform: rotate(90deg);
|
|
18
78
|
}
|
|
19
79
|
|
|
20
80
|
.j-accordion .accordion-panel {
|
|
21
|
-
|
|
81
|
+
margin: var(--accordion-panel-margin);
|
|
82
|
+
font-size: var(--accordion-font-size);
|
|
83
|
+
border-bottom: var(--accordion-border);
|
|
84
|
+
position: relative;
|
|
22
85
|
}
|
|
23
86
|
|
|
24
87
|
.j-accordion .accordion-panel[aria-hidden='false'] {
|
|
25
|
-
|
|
88
|
+
min-height: 2rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.j-accordion[data-direction='horizontal'] .accordion-panel[aria-hidden='false'] {
|
|
92
|
+
border-right: var(--accordion-border);
|
|
93
|
+
border-bottom: 0;
|
|
94
|
+
flex: 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.j-accordion .accordion-panel:last-child {
|
|
98
|
+
border-bottom: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.j-accordion[data-direction='horizontal'] .accordion-panel:last-child {
|
|
102
|
+
border-right: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.j-accordion .accordion-panel .panel-content {
|
|
106
|
+
margin: var(--accordion-panel-content-margin);
|
|
107
|
+
padding: var(--accordion-panel-content-padding);
|
|
108
|
+
position: relative;
|
|
109
|
+
min-height: inherit;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.j-accordion[data-direction='horizontal'] .accordion-panel[aria-hidden='false'] .panel-content {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
justify-content: center;
|
|
116
|
+
height: 100%;
|
|
26
117
|
}
|
|
27
|
-
}
|
|
118
|
+
}
|
package/src/css/content.css
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@layer content {
|
|
2
|
+
|
|
2
3
|
/* ============================================
|
|
3
4
|
Content - 文章阅读/编辑器预览样式
|
|
4
5
|
============================================ */
|
|
@@ -18,12 +19,6 @@
|
|
|
18
19
|
/* ============================================
|
|
19
20
|
Typography - 段落与标题
|
|
20
21
|
============================================ */
|
|
21
|
-
.j-content *,
|
|
22
|
-
.j-content *::before,
|
|
23
|
-
.j-content *::after {
|
|
24
|
-
box-sizing: border-box;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
22
|
.j-content p {
|
|
28
23
|
margin: 0 0 var(--content-paragraph-space);
|
|
29
24
|
}
|
|
@@ -34,8 +29,7 @@
|
|
|
34
29
|
.j-content h4,
|
|
35
30
|
.j-content h5,
|
|
36
31
|
.j-content h6 {
|
|
37
|
-
margin: var(--content-heading-space) 0
|
|
38
|
-
calc(var(--content-heading-space) * 0.75);
|
|
32
|
+
margin: var(--content-heading-space) 0 calc(var(--content-heading-space) * 0.75);
|
|
39
33
|
font-weight: 600;
|
|
40
34
|
line-height: 1.3;
|
|
41
35
|
color: var(--content-heading-fg);
|
|
@@ -70,12 +64,12 @@
|
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
/* 标题后的段落减少间距 */
|
|
73
|
-
.j-content h1
|
|
74
|
-
.j-content h2
|
|
75
|
-
.j-content h3
|
|
76
|
-
.j-content h4
|
|
77
|
-
.j-content h5
|
|
78
|
-
.j-content h6
|
|
67
|
+
.j-content h1+p,
|
|
68
|
+
.j-content h2+p,
|
|
69
|
+
.j-content h3+p,
|
|
70
|
+
.j-content h4+p,
|
|
71
|
+
.j-content h5+p,
|
|
72
|
+
.j-content h6+p {
|
|
79
73
|
margin-top: calc(var(--content-paragraph-space) * -0.5);
|
|
80
74
|
}
|
|
81
75
|
|
|
@@ -255,7 +249,7 @@
|
|
|
255
249
|
color: var(--tone-body);
|
|
256
250
|
}
|
|
257
251
|
|
|
258
|
-
.j-content dd
|
|
252
|
+
.j-content dd+dt {
|
|
259
253
|
margin-top: 1em;
|
|
260
254
|
}
|
|
261
255
|
|
|
@@ -283,7 +277,7 @@
|
|
|
283
277
|
margin: 0;
|
|
284
278
|
}
|
|
285
279
|
|
|
286
|
-
.j-content blockquote p
|
|
280
|
+
.j-content blockquote p+p {
|
|
287
281
|
margin-top: 0.75em;
|
|
288
282
|
}
|
|
289
283
|
|
|
@@ -399,7 +393,7 @@
|
|
|
399
393
|
padding: 1.25em 1.5em;
|
|
400
394
|
}
|
|
401
395
|
|
|
402
|
-
.j-content pre.j-code-editor .code-header
|
|
396
|
+
.j-content pre.j-code-editor .code-header+code[class*='language-'] {
|
|
403
397
|
padding: 0.5rem 1rem 1rem;
|
|
404
398
|
}
|
|
405
399
|
|
|
@@ -647,14 +641,14 @@
|
|
|
647
641
|
transition: transform 0.2s ease;
|
|
648
642
|
}
|
|
649
643
|
|
|
650
|
-
.j-content details[open]
|
|
644
|
+
.j-content details[open]>summary::before {
|
|
651
645
|
transform: rotate(90deg);
|
|
652
646
|
}
|
|
653
647
|
|
|
654
648
|
.j-content details[open] p,
|
|
655
649
|
.j-content details[open] ul,
|
|
656
650
|
.j-content details[open] ol,
|
|
657
|
-
.j-content details[open]
|
|
651
|
+
.j-content details[open]>* {
|
|
658
652
|
margin-bottom: 1em;
|
|
659
653
|
}
|
|
660
654
|
|
|
@@ -662,11 +656,11 @@
|
|
|
662
656
|
margin-bottom: 0.75em;
|
|
663
657
|
} */
|
|
664
658
|
|
|
665
|
-
.j-content details[open]
|
|
659
|
+
.j-content details[open]>summary+* {
|
|
666
660
|
margin-top: 0;
|
|
667
661
|
}
|
|
668
662
|
|
|
669
|
-
.j-content details[open]
|
|
663
|
+
.j-content details[open]>*:last-child {
|
|
670
664
|
margin-bottom: 0;
|
|
671
665
|
}
|
|
672
666
|
|
|
@@ -711,11 +705,11 @@
|
|
|
711
705
|
}
|
|
712
706
|
|
|
713
707
|
/* First/Last child margin reset */
|
|
714
|
-
.j-content
|
|
708
|
+
.j-content>*:first-child {
|
|
715
709
|
margin-top: 0;
|
|
716
710
|
}
|
|
717
711
|
|
|
718
|
-
.j-content
|
|
712
|
+
.j-content>*:last-child {
|
|
719
713
|
margin-bottom: 0;
|
|
720
714
|
}
|
|
721
|
-
}
|
|
715
|
+
}
|
package/src/css/drop.css
CHANGED
package/src/css/form.css
CHANGED
|
@@ -67,6 +67,14 @@
|
|
|
67
67
|
.j-form .form-buttons {
|
|
68
68
|
display: flex;
|
|
69
69
|
gap: var(--form-buttons-gap, var(--s2));
|
|
70
|
+
margin-top: 1rem;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.j-form [data-form-buttons] button {
|
|
74
|
+
position: relative;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.j-form.is-horizontal .form-buttons {
|
|
70
78
|
margin: 0;
|
|
71
79
|
}
|
|
72
80
|
|
package/src/css/menu.css
CHANGED
|
@@ -77,7 +77,10 @@
|
|
|
77
77
|
height: var(--menu-item-icon-size);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
.j-menu
|
|
80
|
+
.j-menu:not([data-menu-type='mobile']):not([data-menu-type='bottom'])
|
|
81
|
+
.menu
|
|
82
|
+
.menu-item.menu-item-has-children
|
|
83
|
+
> a {
|
|
81
84
|
pointer-events: none;
|
|
82
85
|
}
|
|
83
86
|
|
|
@@ -413,14 +416,13 @@
|
|
|
413
416
|
width: 100%;
|
|
414
417
|
visibility: hidden;
|
|
415
418
|
opacity: 0;
|
|
416
|
-
transform: translateX(
|
|
419
|
+
transform: translateX(80%);
|
|
417
420
|
transition:
|
|
421
|
+
transform 0.3s ease-in-out,
|
|
418
422
|
opacity 0.3s ease-in-out,
|
|
419
423
|
visibility 0.3s ease-in-out;
|
|
420
|
-
|
|
421
424
|
max-width: 100%;
|
|
422
425
|
background: var(--ui-bg);
|
|
423
|
-
z-index: -1;
|
|
424
426
|
}
|
|
425
427
|
|
|
426
428
|
.j-menu[data-menu-type='mobile'] .menu .sub-menu .menu-item:hover a {
|
|
@@ -520,11 +522,13 @@
|
|
|
520
522
|
min-width: var(--columns-6xs);
|
|
521
523
|
max-width: var(--columns-2xs);
|
|
522
524
|
left: 50%;
|
|
523
|
-
transform: translateX(-50%);
|
|
525
|
+
transform: translateX(-50%) translateY(100%);
|
|
524
526
|
bottom: calc(100% + var(--space));
|
|
525
527
|
transition:
|
|
528
|
+
transform 0.3s ease-in-out,
|
|
526
529
|
visibility 0.3s ease-in-out,
|
|
527
530
|
opacity 0.3s ease-in-out;
|
|
531
|
+
z-index: -1;
|
|
528
532
|
}
|
|
529
533
|
|
|
530
534
|
.j-menu[data-menu-type='bottom']
|
|
@@ -533,6 +537,7 @@
|
|
|
533
537
|
> .sub-menu {
|
|
534
538
|
opacity: 1;
|
|
535
539
|
visibility: visible;
|
|
540
|
+
transform: translateX(-50%) translateY(0%);
|
|
536
541
|
}
|
|
537
542
|
|
|
538
543
|
.j-menu[data-menu-type='bottom']
|
package/src/css/modal.css
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
max-width: var(--modal-max-width);
|
|
12
12
|
max-height: var(--modal-max-height);
|
|
13
13
|
overflow: hidden;
|
|
14
|
-
animation: animate-fade-in 0.35s ease-in-out;
|
|
15
14
|
display: flex;
|
|
16
15
|
flex-direction: column;
|
|
17
16
|
position: relative;
|
|
@@ -48,6 +47,8 @@
|
|
|
48
47
|
overflow-y: auto;
|
|
49
48
|
overflow-wrap: break-word;
|
|
50
49
|
flex: 1;
|
|
50
|
+
position: relative;
|
|
51
|
+
min-height: 32px;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
.j-modal .modal-body p {
|