vanilla-jui 1.4.8 → 1.5.2
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 +402 -977
- 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 +467 -349
- package/src/components/flow.ts +779 -1133
- package/src/components/form.ts +666 -509
- package/src/components/menu.ts +199 -326
- package/src/components/modal.ts +510 -747
- package/src/components/offcanvas.ts +281 -361
- package/src/components/pagination.ts +207 -374
- package/src/components/swiper.ts +688 -1168
- package/src/components/tabs.ts +468 -788
- 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/color.css +4 -5
- package/src/css/color_p3.css +6 -5
- package/src/css/content.css +18 -24
- package/src/css/drop.css +4 -1
- package/src/css/form.css +8 -0
- package/src/css/gradient.css +64 -131
- package/src/css/layout.css +9 -23
- package/src/css/menu.css +10 -5
- package/src/css/modal.css +2 -1
- package/src/css/offcanvas.css +1 -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/tokens.css +18 -35
- package/src/css/tooltip.css +2 -1
- package/src/index.ts +8 -3
- 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
- package/src/utilities/scheduler.ts +0 -156
|
@@ -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/color.css
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
@layer color {
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* gray, olive,
|
|
8
9
|
* tomato, ruby, pink,
|
|
@@ -11,8 +12,7 @@
|
|
|
11
12
|
* yellow, orange, gold
|
|
12
13
|
*/
|
|
13
14
|
:root,
|
|
14
|
-
.light
|
|
15
|
-
.light-theme {
|
|
15
|
+
.light {
|
|
16
16
|
--white: #ffffff;
|
|
17
17
|
--black: #000000;
|
|
18
18
|
|
|
@@ -497,8 +497,7 @@
|
|
|
497
497
|
--gold-track: #b45309;
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
.dark
|
|
501
|
-
.dark-theme {
|
|
500
|
+
.dark {
|
|
502
501
|
--white: #000000;
|
|
503
502
|
--black: #ffffff;
|
|
504
503
|
|
|
@@ -982,4 +981,4 @@
|
|
|
982
981
|
--gold-indicator: #fbbf24;
|
|
983
982
|
--gold-track: #fbbf24;
|
|
984
983
|
}
|
|
985
|
-
}
|
|
984
|
+
}
|
package/src/css/color_p3.css
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
@layer color {
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* Advanced color mode: display-p3
|
|
8
9
|
*
|
|
@@ -14,9 +15,9 @@
|
|
|
14
15
|
*/
|
|
15
16
|
@supports (color: color(display-p3 1 1 1)) {
|
|
16
17
|
@media (color-gamut: p3) {
|
|
18
|
+
|
|
17
19
|
:root,
|
|
18
|
-
.light
|
|
19
|
-
.light-theme {
|
|
20
|
+
.light {
|
|
20
21
|
/* gray */
|
|
21
22
|
--gray-1: oklch(99.3% 0.0028 259.7);
|
|
22
23
|
--gray-2: oklch(98% 0.0053 259.7);
|
|
@@ -502,8 +503,8 @@
|
|
|
502
503
|
|
|
503
504
|
@supports (color: color(display-p3 1 1 1)) {
|
|
504
505
|
@media (color-gamut: p3) {
|
|
505
|
-
|
|
506
|
-
.dark
|
|
506
|
+
|
|
507
|
+
.dark {
|
|
507
508
|
/* gray */
|
|
508
509
|
--gray-1: oklch(17.8% 0.0034 264.5);
|
|
509
510
|
--gray-2: oklch(21% 0.0035 264.5);
|
|
@@ -986,4 +987,4 @@
|
|
|
986
987
|
}
|
|
987
988
|
}
|
|
988
989
|
}
|
|
989
|
-
}
|
|
990
|
+
}
|
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
|
|