@rvx/ui 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common/theme-test.js +1 -2
- package/dist/common/theme-test.js.map +1 -1
- package/dist/common/theme.d.ts +4 -2
- package/dist/common/theme.js +2 -1
- package/dist/common/theme.js.map +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/button.js +2 -2
- package/dist/components/button.js.map +1 -1
- package/dist/components/checkbox-test.d.ts +3 -0
- package/dist/components/checkbox-test.js +30 -0
- package/dist/components/checkbox-test.js.map +1 -0
- package/dist/components/checkbox.js +5 -8
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/collapse.d.ts +2 -1
- package/dist/components/collapse.js +2 -2
- package/dist/components/collapse.js.map +1 -1
- package/dist/components/column.js +2 -2
- package/dist/components/column.js.map +1 -1
- package/dist/components/control-group.js +1 -2
- package/dist/components/control-group.js.map +1 -1
- package/dist/components/dialog.js +23 -21
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dropdown-input.js.map +1 -1
- package/dist/components/dropdown.js +4 -3
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/flex-space.js +2 -2
- package/dist/components/flex-space.js.map +1 -1
- package/dist/components/heading.d.ts +4 -0
- package/dist/components/heading.js +6 -2
- package/dist/components/heading.js.map +1 -1
- package/dist/components/label.js +2 -2
- package/dist/components/label.js.map +1 -1
- package/dist/components/layer.d.ts +4 -4
- package/dist/components/layer.js +7 -13
- package/dist/components/layer.js.map +1 -1
- package/dist/components/link.js +2 -2
- package/dist/components/link.js.map +1 -1
- package/dist/components/page.js +1 -2
- package/dist/components/page.js.map +1 -1
- package/dist/components/popout.d.ts +2 -1
- package/dist/components/popout.js +59 -58
- package/dist/components/popout.js.map +1 -1
- package/dist/components/popover.js +6 -5
- package/dist/components/popover.js.map +1 -1
- package/dist/components/radio-buttons.js +3 -2
- package/dist/components/radio-buttons.js.map +1 -1
- package/dist/components/row.js +2 -2
- package/dist/components/row.js.map +1 -1
- package/dist/components/scroll-view.js +2 -2
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/text-input.js +2 -2
- package/dist/components/text-input.js.map +1 -1
- package/dist/components/text.js +1 -2
- package/dist/components/text.js.map +1 -1
- package/dist/components/validation.d.ts +4 -3
- package/dist/components/validation.js +6 -7
- package/dist/components/validation.js.map +1 -1
- package/dist/components/value.js +1 -2
- package/dist/components/value.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/test.d.ts +1 -0
- package/dist/test.js +1 -0
- package/dist/test.js.map +1 -1
- package/dist/theme.module.css +108 -41
- package/dist/theme.module.css.map +1 -1
- package/package.json +2 -2
- package/src/common/theme-test.tsx +1 -3
- package/src/common/theme.tsx +4 -2
- package/src/components/button.tsx +3 -4
- package/src/components/checkbox-test.tsx +34 -0
- package/src/components/checkbox.tsx +5 -7
- package/src/components/collapse.tsx +3 -3
- package/src/components/column.tsx +2 -3
- package/src/components/control-group.tsx +2 -3
- package/src/components/dialog.tsx +23 -22
- package/src/components/dropdown-input.tsx +0 -1
- package/src/components/dropdown.tsx +4 -4
- package/src/components/flex-space.tsx +2 -3
- package/src/components/heading.tsx +10 -3
- package/src/components/label.tsx +3 -2
- package/src/components/layer.tsx +13 -19
- package/src/components/link.tsx +2 -3
- package/src/components/page.tsx +2 -3
- package/src/components/popout.tsx +68 -67
- package/src/components/popover.tsx +5 -5
- package/src/components/radio-buttons.tsx +3 -3
- package/src/components/row.tsx +2 -3
- package/src/components/scroll-view.tsx +2 -3
- package/src/components/text-input.tsx +2 -3
- package/src/components/text.tsx +2 -3
- package/src/components/validation.tsx +7 -9
- package/src/components/value.tsx +2 -3
- package/src/index.tsx +2 -2
- package/src/test.tsx +1 -0
- package/src/theme/base.scss +10 -5
- package/src/theme/components/button.scss +58 -31
- package/src/theme/components/control-group.scss +6 -1
- package/src/theme/components/link.scss +1 -1
- package/src/theme/components/text-input.scss +2 -2
package/src/components/layer.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context,
|
|
1
|
+
import { Context, Expression, get, Inject, memo, sig, Signal, teardown, uncapture, untrack, watch } from "rvx";
|
|
2
2
|
|
|
3
3
|
import { Action, handleActionEvent, keyFor } from "../common/events.js";
|
|
4
4
|
|
|
@@ -13,7 +13,7 @@ interface LayerInstance {
|
|
|
13
13
|
autoFocusFallback: Element | undefined;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const LAYER =
|
|
16
|
+
export const LAYER = new Context<LayerHandle>();
|
|
17
17
|
|
|
18
18
|
const LAYERS = sig<LayerInstance[]>([
|
|
19
19
|
{
|
|
@@ -35,19 +35,16 @@ uncapture(() => watch(LAYERS, layers => {
|
|
|
35
35
|
* Render content inside the root layer.
|
|
36
36
|
*/
|
|
37
37
|
export function RootLayer(props: {
|
|
38
|
-
children: (
|
|
38
|
+
children: () => unknown;
|
|
39
39
|
}): unknown {
|
|
40
40
|
const layer = LAYERS.value[0];
|
|
41
41
|
const root = <div
|
|
42
42
|
style={{ display: "contents" }}
|
|
43
43
|
inert={layer.inert}
|
|
44
44
|
>
|
|
45
|
-
<
|
|
46
|
-
{
|
|
47
|
-
|
|
48
|
-
return props.children(ctx);
|
|
49
|
-
}}
|
|
50
|
-
</DeriveContext>
|
|
45
|
+
<Inject context={LAYER} value={new Handle(layer)}>
|
|
46
|
+
{props.children}
|
|
47
|
+
</Inject>
|
|
51
48
|
</div> as HTMLDivElement;
|
|
52
49
|
layer.roots.push(root);
|
|
53
50
|
teardown(() => {
|
|
@@ -67,7 +64,7 @@ export function RootLayer(props: {
|
|
|
67
64
|
* When disposed, focus is moved back to the previously focused element.
|
|
68
65
|
*/
|
|
69
66
|
export function Layer(props: {
|
|
70
|
-
children: (
|
|
67
|
+
children: () => unknown;
|
|
71
68
|
|
|
72
69
|
/**
|
|
73
70
|
* If true, all layers below this one are marked as inert until the current context is disposed.
|
|
@@ -145,12 +142,9 @@ export function Layer(props: {
|
|
|
145
142
|
style={{ display: "contents" }}
|
|
146
143
|
inert={() => layer.inert.value || !enabled()}
|
|
147
144
|
>
|
|
148
|
-
<
|
|
149
|
-
{
|
|
150
|
-
|
|
151
|
-
return props.children(ctx);
|
|
152
|
-
}}
|
|
153
|
-
</DeriveContext>
|
|
145
|
+
<Inject context={LAYER} value={new Handle(layer)}>
|
|
146
|
+
{props.children}
|
|
147
|
+
</Inject>
|
|
154
148
|
</div> as HTMLElement;
|
|
155
149
|
layer.roots.push(root);
|
|
156
150
|
return root;
|
|
@@ -213,14 +207,14 @@ export interface LayerHandle {
|
|
|
213
207
|
* Reactively check if the layer in the current context (or the root layer if there is none) is inert.
|
|
214
208
|
*/
|
|
215
209
|
export function isInertLayer(): boolean {
|
|
216
|
-
return
|
|
210
|
+
return LAYER.current?.inert ?? untrack(() => LAYERS.value[0]).inert.value;
|
|
217
211
|
}
|
|
218
212
|
|
|
219
213
|
/**
|
|
220
214
|
* Reactively check if the layer in the current context (or the root layer if there is none) is the top layer.
|
|
221
215
|
*/
|
|
222
216
|
export function isTopLayer(): boolean {
|
|
223
|
-
return
|
|
217
|
+
return LAYER.current?.top ?? LAYERS.value.length === 1;
|
|
224
218
|
}
|
|
225
219
|
|
|
226
220
|
function instanceContains(instance: LayerInstance, node: Node): boolean {
|
|
@@ -253,7 +247,7 @@ class Handle implements LayerHandle {
|
|
|
253
247
|
useEvent<K extends keyof WindowEventMap>(type: K, listener: (event: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
|
|
254
248
|
useEvent(type: string, listener: (event: Event) => void, options?: boolean | AddEventListenerOptions): void;
|
|
255
249
|
useEvent(type: string, listener: (event: Event) => void, options?: boolean | AddEventListenerOptions): void {
|
|
256
|
-
const wrapper =
|
|
250
|
+
const wrapper = Context.wrap((event: Event): void => {
|
|
257
251
|
if (this.top) {
|
|
258
252
|
listener(event);
|
|
259
253
|
}
|
package/src/components/link.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
1
|
+
import { ClassValue, Expression, get, map, optionalString, StyleValue } from "rvx";
|
|
2
2
|
import { isPending } from "rvx/async";
|
|
3
|
-
|
|
4
3
|
import { Action, handleActionEvent, keyFor } from "../common/events.js";
|
|
5
4
|
import { THEME } from "../common/theme.js";
|
|
6
5
|
import { separated } from "../common/types.js";
|
|
@@ -72,7 +71,7 @@ export function Link(props: {
|
|
|
72
71
|
|
|
73
72
|
children?: unknown;
|
|
74
73
|
}): unknown {
|
|
75
|
-
const theme =
|
|
74
|
+
const theme = THEME.current;
|
|
76
75
|
const disabled = () => isPending() || get(props.disabled);
|
|
77
76
|
|
|
78
77
|
function action(event: Event) {
|
package/src/components/page.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
2
|
-
|
|
1
|
+
import { ClassValue, Expression, StyleValue } from "rvx";
|
|
3
2
|
import { THEME } from "../common/theme.js";
|
|
4
3
|
import { Column } from "./column.js";
|
|
5
4
|
|
|
@@ -11,7 +10,7 @@ export function Page(props: {
|
|
|
11
10
|
style?: StyleValue;
|
|
12
11
|
children?: unknown;
|
|
13
12
|
}): unknown {
|
|
14
|
-
const theme =
|
|
13
|
+
const theme = THEME.current;
|
|
15
14
|
return <div
|
|
16
15
|
role={props.role}
|
|
17
16
|
id={props.id}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { captureSelf,
|
|
2
|
-
|
|
1
|
+
import { captureSelf, Context, Expression, get, render, sig, teardown, TeardownHook, untrack, View, viewNodes } from "rvx";
|
|
2
|
+
import { Emitter, Event as RvxEvent } from "rvx/event";
|
|
3
3
|
import { PASSIVE_ACTION_EVENT } from "../common/events.js";
|
|
4
4
|
import { axisEquals, Direction, DOWN, flip, getBlockStart, getInlineStart, getSize, getWindowSize, getWindowSpaceAround, INSET, LEFT, RIGHT, ScriptDirection, UP, WritingMode } from "../common/writing-mode.js";
|
|
5
5
|
import { LAYER, Layer } from "./layer.js";
|
|
@@ -132,7 +132,6 @@ interface Instance {
|
|
|
132
132
|
* Utility to create automatically placed floating content like popovers or dropdowns.
|
|
133
133
|
*/
|
|
134
134
|
export class Popout {
|
|
135
|
-
#context: ReadonlyContext | undefined;
|
|
136
135
|
#placement: Expression<PopoutPlacement>;
|
|
137
136
|
#alignment: Expression<PopoutAlignment>;
|
|
138
137
|
#content: PopoutContent;
|
|
@@ -149,7 +148,6 @@ export class Popout {
|
|
|
149
148
|
* The popout hides automatically when the current context is disposed.
|
|
150
149
|
*/
|
|
151
150
|
constructor(options: PopoutOptions) {
|
|
152
|
-
this.#context = getContext();
|
|
153
151
|
this.#placement = options.placement;
|
|
154
152
|
this.#alignment = options.alignment;
|
|
155
153
|
this.#content = options.content;
|
|
@@ -167,6 +165,71 @@ export class Popout {
|
|
|
167
165
|
return this.#visible.value;
|
|
168
166
|
}
|
|
169
167
|
|
|
168
|
+
#createInstance = Context.wrap((writingMode: WritingMode, scriptDir: ScriptDirection): Instance => {
|
|
169
|
+
return captureSelf(dispose => {
|
|
170
|
+
const instance: Instance = this.#instance = {
|
|
171
|
+
dispose,
|
|
172
|
+
content: undefined!,
|
|
173
|
+
view: undefined!,
|
|
174
|
+
observer: undefined!,
|
|
175
|
+
sizeReference: undefined,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
instance.view = render(<Layer>
|
|
179
|
+
{() => {
|
|
180
|
+
const layer = LAYER.current!;
|
|
181
|
+
const onForeignEvent = (event: Event): void => {
|
|
182
|
+
if (event.target instanceof Node) {
|
|
183
|
+
if (layer.stackContains(event.target)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const args = this.#instanceArgs;
|
|
187
|
+
if (args !== undefined) {
|
|
188
|
+
for (const node of viewNodes(args.anchor)) {
|
|
189
|
+
if (node === event.target || node.contains(event.target)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
this.hide();
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
this.#foreignEvents.forEach(t => window.addEventListener(t, onForeignEvent, { passive: true, capture: true }));
|
|
199
|
+
teardown(() => {
|
|
200
|
+
this.#foreignEvents.forEach(t => window.removeEventListener(t, onForeignEvent, { capture: true }));
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
instance!.content = <div style={{
|
|
204
|
+
"position": "fixed",
|
|
205
|
+
"writing-mode": writingMode,
|
|
206
|
+
}} dir={scriptDir}>
|
|
207
|
+
{this.#content({
|
|
208
|
+
popout: this,
|
|
209
|
+
onPlacement: this.#onPlacement.event,
|
|
210
|
+
placement: () => this.#placementState.value,
|
|
211
|
+
setSizeReference: target => {
|
|
212
|
+
instance!.sizeReference = target;
|
|
213
|
+
},
|
|
214
|
+
})}
|
|
215
|
+
</div> as HTMLElement;
|
|
216
|
+
return instance!.content;
|
|
217
|
+
}}
|
|
218
|
+
</Layer>);
|
|
219
|
+
document.body.appendChild(instance.view.take());
|
|
220
|
+
|
|
221
|
+
instance.observer = new ResizeObserver(entries => {
|
|
222
|
+
const args = this.#instanceArgs;
|
|
223
|
+
const size = entries[entries.length - 1]?.borderBoxSize[0];
|
|
224
|
+
if (args !== undefined && size !== undefined && (size.blockSize !== args.contentBlockSize || size.inlineSize !== args.contentInlineSize)) {
|
|
225
|
+
this.show(args.anchor, args.pointerEvent);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
instance.observer.observe(instance.content, { box: "border-box" });
|
|
229
|
+
return instance;
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
170
233
|
/**
|
|
171
234
|
* Show the popout or recalculate placement if already visible.
|
|
172
235
|
*
|
|
@@ -223,69 +286,7 @@ export class Popout {
|
|
|
223
286
|
// Ensure that there is a popout content instance:
|
|
224
287
|
let instance = this.#instance;
|
|
225
288
|
if (instance === undefined) {
|
|
226
|
-
|
|
227
|
-
captureSelf(dispose => {
|
|
228
|
-
instance = this.#instance = {
|
|
229
|
-
dispose,
|
|
230
|
-
content: undefined!,
|
|
231
|
-
view: undefined!,
|
|
232
|
-
observer: undefined!,
|
|
233
|
-
sizeReference: undefined,
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
instance.view = render(<Layer>
|
|
237
|
-
{() => {
|
|
238
|
-
const layer = extract(LAYER)!;
|
|
239
|
-
const onForeignEvent = (event: Event): void => {
|
|
240
|
-
if (event.target instanceof Node) {
|
|
241
|
-
if (layer.stackContains(event.target)) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
const args = this.#instanceArgs;
|
|
245
|
-
if (args !== undefined) {
|
|
246
|
-
for (const node of viewNodes(args.anchor)) {
|
|
247
|
-
if (node === event.target || node.contains(event.target)) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
this.hide();
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
this.#foreignEvents.forEach(t => window.addEventListener(t, onForeignEvent, { passive: true, capture: true }));
|
|
257
|
-
teardown(() => {
|
|
258
|
-
this.#foreignEvents.forEach(t => window.removeEventListener(t, onForeignEvent, { capture: true }));
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
instance!.content = <div style={{
|
|
262
|
-
"position": "fixed",
|
|
263
|
-
"writing-mode": writingMode,
|
|
264
|
-
}} dir={scriptDir}>
|
|
265
|
-
{this.#content({
|
|
266
|
-
popout: this,
|
|
267
|
-
onPlacement: this.#onPlacement.event,
|
|
268
|
-
placement: () => this.#placementState.value,
|
|
269
|
-
setSizeReference: target => {
|
|
270
|
-
instance!.sizeReference = target;
|
|
271
|
-
},
|
|
272
|
-
})}
|
|
273
|
-
</div> as HTMLElement;
|
|
274
|
-
return instance!.content;
|
|
275
|
-
}}
|
|
276
|
-
</Layer>);
|
|
277
|
-
document.body.appendChild(instance.view.take());
|
|
278
|
-
|
|
279
|
-
instance.observer = new ResizeObserver(entries => {
|
|
280
|
-
const args = this.#instanceArgs;
|
|
281
|
-
const size = entries[entries.length - 1]?.borderBoxSize[0];
|
|
282
|
-
if (args !== undefined && size !== undefined && (size.blockSize !== args.contentBlockSize || size.inlineSize !== args.contentInlineSize)) {
|
|
283
|
-
this.show(args.anchor, args.pointerEvent);
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
instance.observer.observe(instance.content, { box: "border-box" });
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
+
instance = this.#createInstance(writingMode!, scriptDir!);
|
|
289
290
|
}
|
|
290
291
|
|
|
291
292
|
const placementArgs: PopoutPlacementArgs = { gap: 0 };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
2
|
-
|
|
1
|
+
import { ClassValue, Expression, get, Inject, map, render, sig, StyleValue, SVG, watch, XMLNS } from "rvx";
|
|
2
|
+
import { uniqueId } from "rvx/id";
|
|
3
3
|
import { Action } from "../common/events.js";
|
|
4
4
|
import { THEME } from "../common/theme.js";
|
|
5
5
|
import { DOWN, getSize, getXY, LEFT, RIGHT, UP } from "../common/writing-mode.js";
|
|
@@ -76,8 +76,8 @@ export function createPopover(props: {
|
|
|
76
76
|
placement: map(props.placement, v => v ?? "block"),
|
|
77
77
|
alignment: map(props.alignment, v => v ?? "center"),
|
|
78
78
|
content: ({ popout, onPlacement, placement, setSizeReference }) => {
|
|
79
|
-
const theme =
|
|
80
|
-
const layer =
|
|
79
|
+
const theme = THEME.current;
|
|
80
|
+
const layer = LAYER.current!;
|
|
81
81
|
const spikeTransform = sig("");
|
|
82
82
|
|
|
83
83
|
layer.useHotkey("escape", () => {
|
|
@@ -113,7 +113,7 @@ export function createPopover(props: {
|
|
|
113
113
|
|
|
114
114
|
const spikeArea = <div class={theme?.popover_spike_area}>
|
|
115
115
|
<div class={theme?.popover_spike} style={{ transform: spikeTransform }}>
|
|
116
|
-
<Inject
|
|
116
|
+
<Inject context={XMLNS} value={SVG}>
|
|
117
117
|
{() => {
|
|
118
118
|
return <svg viewBox="0 0 16 16" preserveAspectRatio="none">
|
|
119
119
|
<path d="M0,16 L8,0 L16,16 Z" />
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
1
|
+
import { ClassValue, Expression, For, get, map, optionalString, Signal, string, StyleValue } from "rvx";
|
|
2
2
|
import { isPending } from "rvx/async";
|
|
3
|
-
|
|
4
3
|
import { THEME } from "../common/theme.js";
|
|
5
4
|
import { Text } from "./text.js";
|
|
6
5
|
import { validatorFor } from "./validation.js";
|
|
6
|
+
import { uniqueId } from "rvx/id";
|
|
7
7
|
|
|
8
8
|
export interface RadioOption<T> {
|
|
9
9
|
value: T;
|
|
@@ -26,7 +26,7 @@ export function RadioButtons<T>(props: {
|
|
|
26
26
|
children?: never;
|
|
27
27
|
}): unknown {
|
|
28
28
|
const group = uniqueId();
|
|
29
|
-
const theme =
|
|
29
|
+
const theme = THEME.current;
|
|
30
30
|
|
|
31
31
|
const disabled = props.value instanceof Signal
|
|
32
32
|
? () => isPending() || get(props.disabled)
|
package/src/components/row.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
2
|
-
|
|
1
|
+
import { ClassValue, Expression, get, StyleValue } from "rvx";
|
|
3
2
|
import { THEME } from "../common/theme.js";
|
|
4
3
|
import { SizeContext } from "../common/types.js";
|
|
5
4
|
|
|
@@ -12,7 +11,7 @@ export function Row(props: {
|
|
|
12
11
|
style?: StyleValue;
|
|
13
12
|
children?: unknown;
|
|
14
13
|
}): unknown {
|
|
15
|
-
const theme =
|
|
14
|
+
const theme = THEME.current;
|
|
16
15
|
return <div
|
|
17
16
|
class={[
|
|
18
17
|
theme?.row,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ClassValue,
|
|
2
|
-
|
|
1
|
+
import { ClassValue, sig, StyleValue, teardown } from "rvx";
|
|
3
2
|
import { debounceEvent } from "../common/events.js";
|
|
4
3
|
import { THEME } from "../common/theme.js";
|
|
5
4
|
import { axisEquals, DOWN, getBlockStart, getSize, RIGHT, UP, WritingMode } from "../common/writing-mode.js";
|
|
@@ -9,7 +8,7 @@ export function ScrollView(props: {
|
|
|
9
8
|
style?: StyleValue;
|
|
10
9
|
children?: unknown;
|
|
11
10
|
}): unknown {
|
|
12
|
-
const theme =
|
|
11
|
+
const theme = THEME.current;
|
|
13
12
|
const vertical = sig<boolean | undefined>(undefined);
|
|
14
13
|
const scrollbarComp = sig(0);
|
|
15
14
|
const startIndicator = sig(false);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
1
|
+
import { ClassValue, Expression, get, optionalString, Signal, StyleValue } from "rvx";
|
|
2
2
|
import { isPending, waitFor } from "rvx/async";
|
|
3
|
-
|
|
4
3
|
import { keyFor } from "../common/events.js";
|
|
5
4
|
import { THEME } from "../common/theme.js";
|
|
6
5
|
import { validatorFor } from "./validation.js";
|
|
@@ -64,7 +63,7 @@ export function TextInput(props: ({
|
|
|
64
63
|
"aria-label"?: Expression<string | undefined>;
|
|
65
64
|
"aria-labelledby"?: Expression<string | undefined>;
|
|
66
65
|
}): unknown {
|
|
67
|
-
const theme =
|
|
66
|
+
const theme = THEME.current;
|
|
68
67
|
const disabled = () => isPending() || get(props.disabled);
|
|
69
68
|
|
|
70
69
|
const validator = props.value instanceof Signal ? validatorFor(props.value) : undefined;
|
package/src/components/text.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
2
|
-
|
|
1
|
+
import { ClassValue, Expression, StyleValue } from "rvx";
|
|
3
2
|
import { THEME } from "../common/theme.js";
|
|
4
3
|
|
|
5
4
|
export function Text(props: {
|
|
@@ -8,7 +7,7 @@ export function Text(props: {
|
|
|
8
7
|
id?: Expression<string | undefined>;
|
|
9
8
|
children?: unknown;
|
|
10
9
|
}): unknown {
|
|
11
|
-
const theme =
|
|
10
|
+
const theme = THEME.current;
|
|
12
11
|
return <div
|
|
13
12
|
class={[
|
|
14
13
|
theme?.text,
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { ClassValue,
|
|
1
|
+
import { ClassValue, Context, Expression, For, map, sig, Signal, StyleValue, teardown, trigger, TriggerPipe, untrack } from "rvx";
|
|
2
2
|
import { TaskSlot } from "rvx/async";
|
|
3
|
-
|
|
4
3
|
import { THEME } from "../common/theme.js";
|
|
5
4
|
import { Collapse } from "./collapse.js";
|
|
6
5
|
import { Text } from "./text.js";
|
|
6
|
+
import { uniqueId } from "rvx/id";
|
|
7
|
+
import { Emitter, Event } from "rvx/event";
|
|
7
8
|
|
|
8
9
|
const VALIDATORS = new WeakMap<object, Validator>();
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* Context
|
|
12
|
+
* Context for validation options used by new validators.
|
|
12
13
|
*/
|
|
13
|
-
export const VALIDATION =
|
|
14
|
+
export const VALIDATION = new Context<ValidationOptions>();
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Defines when accessed signals trigger automatic validation.
|
|
@@ -30,10 +31,9 @@ export class Validator {
|
|
|
30
31
|
#signalTrigger: ValidationSignalTrigger;
|
|
31
32
|
#rules = sig<ValidationRuleEntry[]>([]);
|
|
32
33
|
#invalid = sig(false);
|
|
33
|
-
#cycle = 0;
|
|
34
34
|
|
|
35
35
|
constructor() {
|
|
36
|
-
const options =
|
|
36
|
+
const options = VALIDATION.current;
|
|
37
37
|
this.#signalTrigger = options?.signalTrigger ?? "if-validated";
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -98,7 +98,6 @@ export class Validator {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
async #validate(sideEffect: boolean, signal?: AbortSignal): Promise<boolean> {
|
|
101
|
-
this.#cycle++;
|
|
102
101
|
const rules = untrack(() => this.#rules.value);
|
|
103
102
|
for (let i = 0; i < rules.length; i++) {
|
|
104
103
|
if (signal?.aborted) {
|
|
@@ -143,7 +142,6 @@ export class Validator {
|
|
|
143
142
|
* Reset this validator to it's initial state.
|
|
144
143
|
*/
|
|
145
144
|
reset(): void {
|
|
146
|
-
this.#cycle++;
|
|
147
145
|
this.#invalid.value = false;
|
|
148
146
|
const rules = untrack(() => this.#rules.value);
|
|
149
147
|
for (let i = 0; i < rules.length; i++) {
|
|
@@ -238,7 +236,7 @@ export function ValidationMessage(props: {
|
|
|
238
236
|
id?: Expression<string | undefined>;
|
|
239
237
|
children?: unknown;
|
|
240
238
|
}): unknown {
|
|
241
|
-
const theme =
|
|
239
|
+
const theme = THEME.current;
|
|
242
240
|
return <Collapse
|
|
243
241
|
visible={map(props.visible, v => v ?? true)}
|
|
244
242
|
alert={props.alert}
|
package/src/components/value.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ClassValue, Expression,
|
|
2
|
-
|
|
1
|
+
import { ClassValue, Expression, StyleValue } from "rvx";
|
|
3
2
|
import { THEME } from "../common/theme.js";
|
|
4
3
|
|
|
5
4
|
export function Value(props: {
|
|
@@ -8,7 +7,7 @@ export function Value(props: {
|
|
|
8
7
|
id?: Expression<string | undefined>;
|
|
9
8
|
children?: unknown;
|
|
10
9
|
}): unknown {
|
|
11
|
-
const theme =
|
|
10
|
+
const theme = THEME.current;
|
|
12
11
|
return <span
|
|
13
12
|
class={[
|
|
14
13
|
theme?.value,
|
package/src/index.tsx
CHANGED
|
@@ -10,8 +10,8 @@ export * from "./components/collapse.js";
|
|
|
10
10
|
export * from "./components/column.js";
|
|
11
11
|
export * from "./components/control-group.js";
|
|
12
12
|
export * from "./components/dialog.js";
|
|
13
|
-
export * from "./components/dropdown.js";
|
|
14
13
|
export * from "./components/dropdown-input.js";
|
|
14
|
+
export * from "./components/dropdown.js";
|
|
15
15
|
export * from "./components/flex-space.js";
|
|
16
16
|
export * from "./components/heading.js";
|
|
17
17
|
export * from "./components/label.js";
|
|
@@ -23,7 +23,7 @@ export * from "./components/popover.js";
|
|
|
23
23
|
export * from "./components/radio-buttons.js";
|
|
24
24
|
export * from "./components/row.js";
|
|
25
25
|
export * from "./components/scroll-view.js";
|
|
26
|
-
export * from "./components/text.js";
|
|
27
26
|
export * from "./components/text-input.js";
|
|
27
|
+
export * from "./components/text.js";
|
|
28
28
|
export * from "./components/validation.js";
|
|
29
29
|
export * from "./components/value.js";
|
package/src/test.tsx
CHANGED
package/src/theme/base.scss
CHANGED
|
@@ -12,6 +12,9 @@ $root-size: 14px;
|
|
|
12
12
|
font-size: #{math.div(1rem, 16px) * $root-size};
|
|
13
13
|
line-height: 1;
|
|
14
14
|
|
|
15
|
+
--accent: rgb(0, 192, 255);
|
|
16
|
+
accent-color: var(--accent);
|
|
17
|
+
|
|
15
18
|
--content-column-gap: #{px(16)};
|
|
16
19
|
--content-row-gap: #{px(16)};
|
|
17
20
|
--content-radius: #{px(8)};
|
|
@@ -20,8 +23,9 @@ $root-size: 14px;
|
|
|
20
23
|
|
|
21
24
|
--control-column-gap: #{px(8)};
|
|
22
25
|
--control-row-gap: #{px(8)};
|
|
23
|
-
--control-radius: #{px(
|
|
24
|
-
--control-border: #{px(
|
|
26
|
+
--control-radius: #{px(5)};
|
|
27
|
+
--control-border: #{px(2)};
|
|
28
|
+
--control-shadow: 0 0 #{px(3)} rgba(0, 0, 0, .5);
|
|
25
29
|
--control-disabled: opacity(.5);
|
|
26
30
|
@include common.define-quad(control-pad, px(8), px(10));
|
|
27
31
|
|
|
@@ -33,17 +37,18 @@ $root-size: 14px;
|
|
|
33
37
|
--space-gap: #{px(6)};
|
|
34
38
|
|
|
35
39
|
--layout-transition: .15s ease;
|
|
40
|
+
--color-transition: .1s ease;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
@include common.theme((
|
|
39
44
|
bg: (
|
|
40
|
-
dark: rgb(
|
|
45
|
+
dark: rgb(36, 36, 36),
|
|
41
46
|
),
|
|
42
47
|
fg: (
|
|
43
48
|
dark: white,
|
|
44
49
|
),
|
|
45
50
|
focus-outline: (
|
|
46
|
-
dark: var(--control-border) dashed
|
|
51
|
+
dark: var(--control-border) dashed var(--accent),
|
|
47
52
|
),
|
|
48
53
|
));
|
|
49
54
|
|
|
@@ -65,5 +70,5 @@ body {
|
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
::selection {
|
|
68
|
-
background-color: rgba(0,
|
|
73
|
+
background-color: rgba(0, 150, 200, .6);
|
|
69
74
|
}
|