@syware/jlib 0.6.0 → 0.7.0
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/all.js +9 -4
- package/dist/atoms/jl-app-icon.d.ts +5 -0
- package/dist/atoms/jl-app-icon.js +26 -4
- package/dist/atoms/jl-badge.js +1 -1
- package/dist/atoms/jl-button.d.ts +5 -0
- package/dist/atoms/jl-button.js +4 -1
- package/dist/atoms/jl-chip.js +3 -2
- package/dist/atoms/jl-input.js +4 -3
- package/dist/atoms/jl-link.js +1 -1
- package/dist/atoms/jl-rating.js +4 -5
- package/dist/atoms/jl-select.css_raw.js +1 -1
- package/dist/atoms/jl-select.d.ts +3 -2
- package/dist/atoms/jl-select.js +5 -4
- package/dist/atoms/jl-spinner.js +2 -2
- package/dist/base/jl-form-control.js +2 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -3
- package/dist/lib/app-icon.d.ts +8 -0
- package/dist/lib/app-icon.js +37 -0
- package/dist/lib/dom.d.ts +2 -0
- package/dist/lib/dom.js +3 -1
- package/dist/lib/download.d.ts +10 -0
- package/dist/lib/download.js +62 -0
- package/dist/lib/icons.d.ts +4 -0
- package/dist/lib/icons.js +7 -4
- package/dist/lib/input-list.d.ts +12 -0
- package/dist/lib/input-list.js +14 -0
- package/dist/lib/internals.d.ts +5 -0
- package/dist/lib/internals.js +18 -0
- package/dist/lib/palette.js +6 -0
- package/dist/lib/resize.d.ts +2 -0
- package/dist/lib/resize.js +10 -0
- package/dist/lib/table.d.ts +6 -1
- package/dist/lib/table.js +16 -1
- package/dist/lib/text.d.ts +2 -0
- package/dist/lib/text.js +4 -1
- package/dist/lib/texts.d.ts +97 -0
- package/dist/lib/texts.js +102 -0
- package/dist/lib/tree.d.ts +10 -1
- package/dist/lib/tree.js +37 -3
- package/dist/molecules/jl-account-button.js +1 -1
- package/dist/molecules/jl-alert.js +2 -1
- package/dist/molecules/jl-breadcrumb.js +3 -3
- package/dist/molecules/jl-calendar.js +4 -4
- package/dist/molecules/jl-chip-group.js +2 -2
- package/dist/molecules/jl-code-block.css_raw.js +1 -1
- package/dist/molecules/jl-code-block.d.ts +5 -0
- package/dist/molecules/jl-code-block.js +5 -2
- package/dist/molecules/jl-combobox.js +5 -6
- package/dist/molecules/jl-copy-button.js +5 -4
- package/dist/molecules/jl-date-picker.js +6 -7
- package/dist/molecules/jl-empty.js +1 -1
- package/dist/molecules/jl-facts.css_raw.js +3 -0
- package/dist/molecules/jl-facts.d.ts +35 -0
- package/dist/molecules/jl-facts.js +64 -0
- package/dist/molecules/jl-file-drop.d.ts +5 -0
- package/dist/molecules/jl-file-drop.js +17 -14
- package/dist/molecules/jl-input-list.css_raw.js +3 -0
- package/dist/molecules/jl-input-list.d.ts +79 -0
- package/dist/molecules/jl-input-list.js +177 -0
- package/dist/molecules/jl-load-more.css_raw.js +3 -0
- package/dist/molecules/jl-load-more.d.ts +41 -0
- package/dist/molecules/jl-load-more.js +62 -0
- package/dist/molecules/jl-load-state.js +6 -7
- package/dist/molecules/jl-number-input.js +4 -4
- package/dist/molecules/jl-pagination.js +5 -5
- package/dist/molecules/jl-radio-group.js +2 -2
- package/dist/molecules/jl-search-button.js +4 -4
- package/dist/molecules/jl-search.js +4 -4
- package/dist/molecules/jl-segmented.js +2 -1
- package/dist/molecules/jl-steps.css_raw.js +1 -1
- package/dist/molecules/jl-steps.d.ts +2 -0
- package/dist/molecules/jl-steps.js +30 -14
- package/dist/molecules/jl-tabs.js +2 -1
- package/dist/molecules/jl-tag-input.js +2 -2
- package/dist/molecules/jl-toast.css_raw.js +1 -1
- package/dist/molecules/jl-toast.d.ts +13 -1
- package/dist/molecules/jl-toast.js +23 -3
- package/dist/organisms/jl-command-palette.css_raw.js +1 -1
- package/dist/organisms/jl-command-palette.d.ts +14 -0
- package/dist/organisms/jl-command-palette.js +39 -9
- package/dist/organisms/jl-confirm.js +5 -7
- package/dist/organisms/jl-dialog.js +2 -1
- package/dist/organisms/jl-drawer.js +2 -1
- package/dist/organisms/jl-flow.js +12 -12
- package/dist/organisms/jl-navbar.js +6 -6
- package/dist/organisms/jl-side-nav.css_raw.js +1 -1
- package/dist/organisms/jl-side-nav.d.ts +33 -1
- package/dist/organisms/jl-side-nav.js +70 -13
- package/dist/organisms/jl-tab-bar.js +2 -2
- package/dist/organisms/jl-table.css_raw.js +1 -1
- package/dist/organisms/jl-table.d.ts +9 -0
- package/dist/organisms/jl-table.js +35 -5
- package/dist/organisms/jl-toaster.d.ts +9 -1
- package/dist/organisms/jl-toaster.js +148 -7
- package/dist/organisms/jl-tree.css_raw.js +1 -1
- package/dist/organisms/jl-tree.d.ts +71 -4
- package/dist/organisms/jl-tree.js +303 -40
- package/dist/templates/jl-app-shell.css_raw.js +1 -1
- package/dist/templates/jl-app-shell.d.ts +10 -0
- package/dist/templates/jl-app-shell.js +16 -2
- package/dist/templates/jl-auth-layout.js +1 -1
- package/dist/templates/jl-page.js +3 -3
- package/dist/templates/jl-split-view.js +5 -4
- package/dist/types/jl-app-icon.types.d.ts +5 -0
- package/dist/types/jl-command-palette.types.d.ts +7 -0
- package/dist/types/jl-facts.types.d.ts +17 -0
- package/dist/types/jl-side-nav.types.d.ts +2 -0
- package/dist/types/jl-steps.types.d.ts +2 -0
- package/dist/types/jl-table.types.d.ts +9 -2
- package/dist/types/jl-toaster.types.d.ts +42 -1
- package/dist/types/jl-tree.types.d.ts +26 -0
- package/dist/types/texts.types.d.ts +5 -0
- package/package.json +3 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
/**
|
|
3
|
+
* The end of a long list read a page at a time: how much of it shows ("30 of 120") and a button that asks for the
|
|
4
|
+
* next page (`more`). It shows the button's spinner while `loading`, and takes no room once the whole list shows.
|
|
5
|
+
*/
|
|
6
|
+
export declare class JlLoadMore extends JlElement {
|
|
7
|
+
static readonly selector = "jl-load-more";
|
|
8
|
+
readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
|
|
9
|
+
more: undefined;
|
|
10
|
+
}>>;
|
|
11
|
+
/** How many items the list shows. */
|
|
12
|
+
readonly shown: Readonly<Readonly<{
|
|
13
|
+
get(): number;
|
|
14
|
+
set(setter: number | ((prevState: number) => number)): void;
|
|
15
|
+
}>>;
|
|
16
|
+
/** How many it has in all. */
|
|
17
|
+
readonly total: Readonly<Readonly<{
|
|
18
|
+
get(): number;
|
|
19
|
+
set(setter: number | ((prevState: number) => number)): void;
|
|
20
|
+
}>>;
|
|
21
|
+
/** The next page is on its way: the button shows a spinner and ignores presses. */
|
|
22
|
+
readonly loading: Readonly<Readonly<{
|
|
23
|
+
get(): boolean;
|
|
24
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
25
|
+
}>>;
|
|
26
|
+
/** The button's text. */
|
|
27
|
+
readonly label: Readonly<Readonly<{
|
|
28
|
+
get(): string;
|
|
29
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
30
|
+
}>>;
|
|
31
|
+
/** What shows beside it; `{shown}` and `{total}` are filled. */
|
|
32
|
+
readonly countText: Readonly<Readonly<{
|
|
33
|
+
get(): string;
|
|
34
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
35
|
+
}>>;
|
|
36
|
+
private readonly _refs;
|
|
37
|
+
templateHtml(): Node;
|
|
38
|
+
templateCss(): string;
|
|
39
|
+
onConnect(): void;
|
|
40
|
+
private render;
|
|
41
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
|
+
import { JlElement } from "../base/jl-element.js";
|
|
3
|
+
import { fillText } from "../lib/text.js";
|
|
4
|
+
import { jlText } from "../lib/texts.js";
|
|
5
|
+
import { JlButton } from "../atoms/jl-button.js";
|
|
6
|
+
import { pageLocale } from "../lib/locale.js";
|
|
7
|
+
import jl_load_more_default from "./jl-load-more.css_raw.js";
|
|
8
|
+
import { css } from "@jadis/core";
|
|
9
|
+
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
10
|
+
// src/molecules/jl-load-more.tsx
|
|
11
|
+
/**
|
|
12
|
+
* The end of a long list read a page at a time: how much of it shows ("30 of 120") and a button that asks for the
|
|
13
|
+
* next page (`more`). It shows the button's spinner while `loading`, and takes no room once the whole list shows.
|
|
14
|
+
*/
|
|
15
|
+
var JlLoadMore = class extends JlElement {
|
|
16
|
+
static selector = "jl-load-more";
|
|
17
|
+
events = this.useEvents();
|
|
18
|
+
/** How many items the list shows. */
|
|
19
|
+
shown = this.useChange(0, () => this.render(), { attribute: "shown" });
|
|
20
|
+
/** How many it has in all. */
|
|
21
|
+
total = this.useChange(0, () => this.render(), { attribute: "total" });
|
|
22
|
+
/** The next page is on its way: the button shows a spinner and ignores presses. */
|
|
23
|
+
loading = this.useChange(false, (value) => this._refs.button.loading.set(value), { attribute: "loading" });
|
|
24
|
+
/** The button's text. */
|
|
25
|
+
label = this.useChange(jlText("showMore"), (value) => this._refs.button.label.set(value), { attribute: "label" });
|
|
26
|
+
/** What shows beside it; `{shown}` and `{total}` are filled. */
|
|
27
|
+
countText = this.useChange(jlText("shownOfTotal"), () => this.render(), { attribute: "count-text" });
|
|
28
|
+
_refs = this.useRefs((ref) => ({
|
|
29
|
+
button: ref(JlButton),
|
|
30
|
+
count: ref(".count")
|
|
31
|
+
}));
|
|
32
|
+
templateHtml() {
|
|
33
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
34
|
+
class: "more",
|
|
35
|
+
attrs: { part: "base" },
|
|
36
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
37
|
+
class: "count",
|
|
38
|
+
"aria-live": "polite"
|
|
39
|
+
}), /* @__PURE__ */ jsx(JlButton, { size: "sm" })]
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
templateCss() {
|
|
43
|
+
return css`${BASE_STYLES}${jl_load_more_default}`;
|
|
44
|
+
}
|
|
45
|
+
onConnect() {
|
|
46
|
+
this._refs.button.events.register("press", () => {
|
|
47
|
+
if (!this.loading.get()) this.events.emit("more");
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
render() {
|
|
51
|
+
const locale = pageLocale();
|
|
52
|
+
const shown = this.shown.get();
|
|
53
|
+
const total = this.total.get();
|
|
54
|
+
this._refs.count.textContent = fillText(this.countText.get(), {
|
|
55
|
+
shown: shown.toLocaleString(locale),
|
|
56
|
+
total: total.toLocaleString(locale)
|
|
57
|
+
});
|
|
58
|
+
this.reflect("complete", shown >= total);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
JlLoadMore.register();
|
|
62
|
+
export { JlLoadMore };
|
|
@@ -3,6 +3,7 @@ import { JlElement } from "../base/jl-element.js";
|
|
|
3
3
|
import { clampedNumber, oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { define } from "../lib/define.js";
|
|
5
5
|
import { registerIcons } from "../lib/icons.js";
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
6
7
|
import { JlButton } from "../atoms/jl-button.js";
|
|
7
8
|
import { JlSkeleton } from "../atoms/jl-skeleton.js";
|
|
8
9
|
import { JlEmpty } from "./jl-empty.js";
|
|
@@ -28,8 +29,6 @@ var LOAD_SKELETONS = [
|
|
|
28
29
|
"lines"
|
|
29
30
|
];
|
|
30
31
|
var DEFAULT_ERROR_HEADING = "This could not be loaded";
|
|
31
|
-
var DEFAULT_ERROR_TEXT = "Check the connection, then try again. Nothing was changed.";
|
|
32
|
-
var DEFAULT_RETRY_LABEL = "Try again";
|
|
33
32
|
var DEFAULT_DELAY_MS = 300;
|
|
34
33
|
var MAX_DELAY_MS = 5e3;
|
|
35
34
|
var DEFAULT_COUNT = 3;
|
|
@@ -95,14 +94,14 @@ var JlLoadState = class extends JlElement {
|
|
|
95
94
|
parse: clampedNumber(DEFAULT_DELAY_MS, 0, MAX_DELAY_MS)
|
|
96
95
|
});
|
|
97
96
|
errorHeading = this.useChange(DEFAULT_ERROR_HEADING, (value) => this._refs.error.heading.set(value), { attribute: "error-heading" });
|
|
98
|
-
errorText = this.useChange(
|
|
99
|
-
retryLabel = this.useChange(
|
|
97
|
+
errorText = this.useChange(jlText("loadStateError"), (value) => this._refs.error.description.set(value), { attribute: "error-text" });
|
|
98
|
+
retryLabel = this.useChange(jlText("retry"), (value) => this._refs.retry.label.set(value), { attribute: "retry-label" });
|
|
100
99
|
_work = { latest: 0 };
|
|
101
100
|
_refs = this.useRefs((ref) => ({
|
|
102
101
|
bones: ref(".bones"),
|
|
103
102
|
content: ref(".content"),
|
|
104
103
|
empty: ref(".empty"),
|
|
105
|
-
error: ref(
|
|
104
|
+
error: ref(JlEmpty),
|
|
106
105
|
loading: ref(".loading"),
|
|
107
106
|
retry: ref(".retry")
|
|
108
107
|
}));
|
|
@@ -152,12 +151,12 @@ var JlLoadState = class extends JlElement {
|
|
|
152
151
|
class: "error",
|
|
153
152
|
icon: "circle-alert",
|
|
154
153
|
heading: DEFAULT_ERROR_HEADING,
|
|
155
|
-
description:
|
|
154
|
+
description: jlText("loadStateError"),
|
|
156
155
|
hidden: true,
|
|
157
156
|
children: /* @__PURE__ */ jsx(JlButton, {
|
|
158
157
|
class: "retry",
|
|
159
158
|
icon: "refresh",
|
|
160
|
-
label:
|
|
159
|
+
label: jlText("retry")
|
|
161
160
|
})
|
|
162
161
|
}),
|
|
163
162
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -3,6 +3,7 @@ import { JlFormControl } from "../base/jl-form-control.js";
|
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
5
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
6
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
7
8
|
import { setOrRemove } from "../lib/dom.js";
|
|
8
9
|
import { clamp, parseNumber, stepValue } from "../lib/numeric.js";
|
|
@@ -18,7 +19,6 @@ registerIcons({
|
|
|
18
19
|
var DEFAULT_STEP = 1;
|
|
19
20
|
var PAGE_STEPS = 10;
|
|
20
21
|
var ICON_SIZE = 14;
|
|
21
|
-
var VALUE_MISSING = "Please fill in this field.";
|
|
22
22
|
var positiveStep = (value) => {
|
|
23
23
|
const parsed = parseNumber(value);
|
|
24
24
|
return parsed === null || parsed <= 0 ? DEFAULT_STEP : parsed;
|
|
@@ -89,7 +89,7 @@ var JlNumberInput = class extends JlFormControl {
|
|
|
89
89
|
class: "action step down",
|
|
90
90
|
type: "button",
|
|
91
91
|
tabIndex: -1,
|
|
92
|
-
"aria-label": "
|
|
92
|
+
"aria-label": jlText("decrease"),
|
|
93
93
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
94
94
|
name: "minus",
|
|
95
95
|
size: ICON_SIZE
|
|
@@ -106,7 +106,7 @@ var JlNumberInput = class extends JlFormControl {
|
|
|
106
106
|
class: "action step up",
|
|
107
107
|
type: "button",
|
|
108
108
|
tabIndex: -1,
|
|
109
|
-
"aria-label": "
|
|
109
|
+
"aria-label": jlText("increase"),
|
|
110
110
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
111
111
|
name: "plus",
|
|
112
112
|
size: ICON_SIZE
|
|
@@ -213,7 +213,7 @@ var JlNumberInput = class extends JlFormControl {
|
|
|
213
213
|
this.internals.setValidity({});
|
|
214
214
|
return;
|
|
215
215
|
}
|
|
216
|
-
this.internals.setValidity({ valueMissing: true },
|
|
216
|
+
this.internals.setValidity({ valueMissing: true }, jlText("fillField"), this._refs.native);
|
|
217
217
|
}
|
|
218
218
|
};
|
|
219
219
|
JlNumberInput.register();
|
|
@@ -3,6 +3,7 @@ import { JlElement } from "../base/jl-element.js";
|
|
|
3
3
|
import { clampedNumber, oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
5
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
6
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
7
8
|
import { clampPage, pageItems } from "../lib/pagination.js";
|
|
8
9
|
import jl_pagination_default from "./jl-pagination.css_raw.js";
|
|
@@ -19,7 +20,6 @@ var ICON_SIZES = {
|
|
|
19
20
|
md: 16,
|
|
20
21
|
sm: 14
|
|
21
22
|
};
|
|
22
|
-
var DEFAULT_LABEL = "Pagination";
|
|
23
23
|
var MAX_PAGES = Number.MAX_SAFE_INTEGER;
|
|
24
24
|
var MAX_NEIGHBOURS = 5;
|
|
25
25
|
var STEP_BACK = -1;
|
|
@@ -61,8 +61,8 @@ var JlPagination = class extends JlElement {
|
|
|
61
61
|
parse: oneOf(CONTROL_SIZES, "md")
|
|
62
62
|
});
|
|
63
63
|
/** The navigation's name for screen readers, when a page has more than one. */
|
|
64
|
-
label = this.useChange(
|
|
65
|
-
this._refs.nav.setAttribute("aria-label", value ||
|
|
64
|
+
label = this.useChange(jlText("pagination"), (value) => {
|
|
65
|
+
this._refs.nav.setAttribute("aria-label", value || jlText("pagination"));
|
|
66
66
|
}, { attribute: "label" });
|
|
67
67
|
_refs = this.useRefs((ref) => ({
|
|
68
68
|
list: ref(".pages"),
|
|
@@ -80,7 +80,7 @@ var JlPagination = class extends JlElement {
|
|
|
80
80
|
/* @__PURE__ */ jsx("button", {
|
|
81
81
|
type: "button",
|
|
82
82
|
class: "button previous",
|
|
83
|
-
"aria-label": "
|
|
83
|
+
"aria-label": jlText("previousPage"),
|
|
84
84
|
children: /* @__PURE__ */ jsx(JlIcon, { name: "chevron-left" })
|
|
85
85
|
}),
|
|
86
86
|
/* @__PURE__ */ jsx("ol", { class: "pages" }),
|
|
@@ -91,7 +91,7 @@ var JlPagination = class extends JlElement {
|
|
|
91
91
|
/* @__PURE__ */ jsx("button", {
|
|
92
92
|
type: "button",
|
|
93
93
|
class: "button next",
|
|
94
|
-
"aria-label": "
|
|
94
|
+
"aria-label": jlText("nextPage"),
|
|
95
95
|
children: /* @__PURE__ */ jsx(JlIcon, { name: "chevron-right" })
|
|
96
96
|
})
|
|
97
97
|
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
2
|
import { JlFormControl } from "../base/jl-form-control.js";
|
|
3
3
|
import { jsonOf, oneOf } from "../lib/attributes.js";
|
|
4
|
+
import { jlText } from "../lib/texts.js";
|
|
4
5
|
import { rovingIndex } from "../lib/roving-index.js";
|
|
5
6
|
import jl_radio_group_default from "./jl-radio-group.css_raw.js";
|
|
6
7
|
import { css } from "@jadis/core";
|
|
@@ -10,7 +11,6 @@ var RADIO_GROUP_ORIENTATIONS = ["vertical", "horizontal"];
|
|
|
10
11
|
var RADIO_GROUP_VARIANTS = ["plain", "cards"];
|
|
11
12
|
var NO_VALUE = "";
|
|
12
13
|
var OPTION_SELECTOR = "[role=\"radio\"]";
|
|
13
|
-
var VALUE_MISSING = "Please select one of these options.";
|
|
14
14
|
/** The keys that move the choice, as with native radios: both arrow pairs whatever the orientation. */
|
|
15
15
|
var MOVES = /* @__PURE__ */ new Map([
|
|
16
16
|
["ArrowDown", "next"],
|
|
@@ -195,7 +195,7 @@ var JlRadioGroup = class extends JlFormControl {
|
|
|
195
195
|
this.internals.setValidity({});
|
|
196
196
|
return;
|
|
197
197
|
}
|
|
198
|
-
this.internals.setValidity({ valueMissing: true },
|
|
198
|
+
this.internals.setValidity({ valueMissing: true }, jlText("selectOption"), this.radios()[0] ?? this._refs.group);
|
|
199
199
|
}
|
|
200
200
|
};
|
|
201
201
|
JlRadioGroup.register();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { registerIcons } from "../lib/icons.js";
|
|
4
|
+
import { jlText } from "../lib/texts.js";
|
|
4
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
5
6
|
import { setOrRemove } from "../lib/dom.js";
|
|
6
7
|
import { JlKbd } from "../atoms/jl-kbd.js";
|
|
@@ -11,7 +12,6 @@ import { Search } from "lucide";
|
|
|
11
12
|
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
12
13
|
// src/molecules/jl-search-button.tsx
|
|
13
14
|
registerIcons({ search: Search });
|
|
14
|
-
var DEFAULT_LABEL = "Search";
|
|
15
15
|
var DEFAULT_HOTKEY = "mod+k";
|
|
16
16
|
var NO_HOTKEY = "none";
|
|
17
17
|
var ICON_SIZE = 15;
|
|
@@ -26,14 +26,14 @@ var JlSearchButton = class extends JlElement {
|
|
|
26
26
|
static selector = "jl-search-button";
|
|
27
27
|
events = this.useEvents();
|
|
28
28
|
/** The text, and the button's name: "Search". */
|
|
29
|
-
label = this.useChange(
|
|
29
|
+
label = this.useChange(jlText("search"), () => this.renderLabel(), { attribute: "label" });
|
|
30
30
|
/** The keys that open the palette, as `jl-kbd` writes them: `mod+k`; `none` for no keys. */
|
|
31
31
|
hotkey = this.useChange(DEFAULT_HOTKEY, () => this.renderHotkey(), { attribute: "hotkey" });
|
|
32
32
|
/** The icon alone, the label as its tooltip. */
|
|
33
33
|
compact = this.useChange(false, (value) => this.reflect("compact", value), { attribute: "compact" });
|
|
34
34
|
_refs = this.useRefs((ref) => ({
|
|
35
35
|
button: ref("button"),
|
|
36
|
-
keys: ref(
|
|
36
|
+
keys: ref(JlKbd),
|
|
37
37
|
text: ref(".text")
|
|
38
38
|
}));
|
|
39
39
|
focus(options) {
|
|
@@ -63,7 +63,7 @@ var JlSearchButton = class extends JlElement {
|
|
|
63
63
|
this.on(this._refs.button, "click", () => this.events.emit("press"));
|
|
64
64
|
}
|
|
65
65
|
renderLabel() {
|
|
66
|
-
const label = this.label.get() ||
|
|
66
|
+
const label = this.label.get() || jlText("search");
|
|
67
67
|
this._refs.text.textContent = label;
|
|
68
68
|
this._refs.button.setAttribute("aria-label", label);
|
|
69
69
|
this._refs.button.title = label;
|
|
@@ -3,6 +3,7 @@ import { JlFormControl } from "../base/jl-form-control.js";
|
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
5
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
6
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
7
8
|
import { setOrRemove } from "../lib/dom.js";
|
|
8
9
|
import { JlSpinner } from "../atoms/jl-spinner.js";
|
|
@@ -19,7 +20,6 @@ registerIcons({
|
|
|
19
20
|
var DEFAULT_DEBOUNCE_MS = 250;
|
|
20
21
|
var ICON_SIZE = 16;
|
|
21
22
|
var ACTION_ICON_SIZE = 14;
|
|
22
|
-
var DEFAULT_LABEL = "Search";
|
|
23
23
|
var MAC_PATTERN = /Mac|iPhone|iPad|iPod/;
|
|
24
24
|
var TYPING_TARGETS = "input, textarea, select, [contenteditable]";
|
|
25
25
|
var isMac = () => MAC_PATTERN.test(navigator.userAgent);
|
|
@@ -38,7 +38,7 @@ var JlSearch = class extends JlFormControl {
|
|
|
38
38
|
value = this.useChange("", (value) => this.renderValue(value), { attribute: "value" });
|
|
39
39
|
placeholder = this.useChange("", (value) => setOrRemove(this._refs.native, "placeholder", value), { attribute: "placeholder" });
|
|
40
40
|
/** The field's name for screen readers; "Search" when nothing else names it. */
|
|
41
|
-
label = this.useChange("", (value) => this._refs.native.setAttribute("aria-label", value ||
|
|
41
|
+
label = this.useChange("", (value) => this._refs.native.setAttribute("aria-label", value || jlText("search")), { attribute: "label" });
|
|
42
42
|
/** How long typing must pause, in milliseconds, before `search` fires. */
|
|
43
43
|
debounce = this.useChange(DEFAULT_DEBOUNCE_MS, () => void 0, { attribute: "debounce" });
|
|
44
44
|
/** Keys that focus the field from anywhere: "/" or "mod+k" (⌘ on a Mac, Ctrl elsewhere). */
|
|
@@ -68,7 +68,7 @@ var JlSearch = class extends JlFormControl {
|
|
|
68
68
|
icon: ref(".icon"),
|
|
69
69
|
keys: ref(".keys"),
|
|
70
70
|
native: ref("input"),
|
|
71
|
-
spinner: ref(
|
|
71
|
+
spinner: ref(JlSpinner)
|
|
72
72
|
}));
|
|
73
73
|
focus(options) {
|
|
74
74
|
this._refs.native.focus(options);
|
|
@@ -108,7 +108,7 @@ var JlSearch = class extends JlFormControl {
|
|
|
108
108
|
/* @__PURE__ */ jsx("button", {
|
|
109
109
|
class: "action clear",
|
|
110
110
|
type: "button",
|
|
111
|
-
"aria-label": "
|
|
111
|
+
"aria-label": jlText("clearSearch"),
|
|
112
112
|
tabIndex: -1,
|
|
113
113
|
hidden: true,
|
|
114
114
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
@@ -6,6 +6,7 @@ import { JlIcon } from "../atoms/jl-icon.js";
|
|
|
6
6
|
import { setOrRemove } from "../lib/dom.js";
|
|
7
7
|
import { firstIndex, lastIndex, stepIndex } from "../lib/roving.js";
|
|
8
8
|
import { moveIndicator } from "../lib/indicator.js";
|
|
9
|
+
import { watchSizes } from "../lib/resize.js";
|
|
9
10
|
import jl_segmented_default from "./jl-segmented.css_raw.js";
|
|
10
11
|
import { css } from "@jadis/core";
|
|
11
12
|
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
@@ -55,7 +56,7 @@ var JlSegmented = class extends JlFormControl {
|
|
|
55
56
|
/** The group's name for screen readers, when no visible label names it. */
|
|
56
57
|
label = this.useChange("", (value) => setOrRemove(this._refs.group, "aria-label", value), { attribute: "label" });
|
|
57
58
|
_state = { disabledByForm: false };
|
|
58
|
-
_resize =
|
|
59
|
+
_resize = watchSizes(() => this.placeThumb());
|
|
59
60
|
_refs = this.useRefs((ref) => ({
|
|
60
61
|
group: ref(".group"),
|
|
61
62
|
thumb: ref(".thumb")
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-steps.css?raw
|
|
2
|
-
var jl_steps_default = ":host {\n display: block;\n container-type: inline-size;\n --marker: 28px;\n}\n\nol {\n display: flex;\n padding: 0;\n list-style: none;\n}\n\n.step {\n display: flex;\n flex: 1;\n min-width: 0;\n}\n\n.step:last-child {\n flex: none;\n}\n\n.head {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n padding: 0;\n border: none;\n border-radius: var(--jl-radius-xs);\n background: none;\n text-align: start;\n}\n\nbutton.head {\n cursor: pointer;\n}\n\n.marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--marker);\n height: var(--marker);\n border: 1px solid var(--jl-line-strong);\n border-radius: 50%;\n background: var(--jl-surface);\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 650;\n font-variant-numeric: tabular-nums;\n}\n\n.text {\n display: grid;\n gap: 2px;\n min-width: 0;\n padding-top: 4px;\n}\n\n.label {\n color: var(--jl-muted);\n font-size: var(--jl-font-md);\n font-weight: 600;\n line-height: 20px;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.45;\n}\n\n.step[data-status=\"done\"] .marker {\n border-color: var(--jl-accent-line);\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n.step[data-status=\"done\"] .label {\n color: var(--jl-text);\n}\n\n.step[data-status=\"current\"] .marker {\n border-color: var(--jl-accent);\n background: var(--jl-accent);\n color: var(--jl-on-accent);\n box-shadow: 0 0 0 4px var(--jl-accent-soft);\n}\n\n.step[data-status=\"current\"] .label {\n color: var(--jl-accent);\n font-weight: 700;\n}\n\nbutton.head:hover .label {\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n\n.line {\n flex: 1;\n min-width: 24px;\n height: 1px;\n /* Further from the label before it than from the next marker: a label reads as its own step's. */\n margin: calc(var(--marker) / 2) 12px 0 20px;\n background: var(--jl-line-strong);\n}\n\n.step[data-status=\"done\"] .line {\n background: var(--jl-accent);\n}\n\n.step:last-child .line {\n display: none;\n}\n\n/* Vertical: the markers in a column joined by a rule, the text beside them. */\n:host([orientation=\"vertical\"]) ol {\n flex-direction: column;\n}\n\n:host([orientation=\"vertical\"]) .step {\n position: relative;\n flex: none;\n padding-bottom: 24px;\n}\n\n:host([orientation=\"vertical\"]) .step:last-child {\n padding-bottom: 0;\n}\n\n:host([orientation=\"vertical\"]) .line {\n position: absolute;\n top: calc(var(--marker) + 4px);\n bottom: 4px;\n left: calc(var(--marker) / 2 - 0.5px);\n width: 1px;\n height: auto;\n min-width: 0;\n margin: 0;\n}\n\n/* Narrow, the horizontal steps keep their markers and only the current step's text. */\n@container (width < 560px) {\n /* Out of sight, still read: the same rules as .sr-only. */\n :host(:not([orientation=\"vertical\"])) .step:not([data-status=\"current\"]) .text {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n }\n\n :host(:not([orientation=\"vertical\"])) .description {\n display: none;\n }\n\n :host(:not([orientation=\"vertical\"])) .line {\n min-width: 8px;\n margin: calc(var(--marker) / 2) 8px 0;\n }\n\n /* The current step takes three shares of the room, the others one, never less than their marker and line: the\n label never runs into the next step, and takes an ellipsis only when there is no room at all. */\n :host(:not([orientation=\"vertical\"])) .step:not([data-status=\"current\"]) {\n min-width: min-content;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] {\n flex: 3 1 0;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] .label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] .line {\n min-width: 24px;\n margin-left: 16px;\n }\n}\n";
|
|
2
|
+
var jl_steps_default = ":host {\n display: block;\n container-type: inline-size;\n --marker: 28px;\n}\n\nol {\n display: flex;\n padding: 0;\n list-style: none;\n}\n\n.step {\n display: flex;\n flex: 1;\n min-width: 0;\n}\n\n.step:last-child {\n flex: none;\n}\n\n.head {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n padding: 0;\n border: none;\n border-radius: var(--jl-radius-xs);\n background: none;\n text-align: start;\n}\n\nbutton.head {\n cursor: pointer;\n}\n\n.marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--marker);\n height: var(--marker);\n border: 1px solid var(--jl-line-strong);\n border-radius: 50%;\n background: var(--jl-surface);\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n font-weight: 650;\n font-variant-numeric: tabular-nums;\n}\n\n.text {\n display: grid;\n gap: 2px;\n min-width: 0;\n padding-top: 4px;\n}\n\n.label {\n color: var(--jl-muted);\n font-size: var(--jl-font-md);\n font-weight: 600;\n line-height: 20px;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n line-height: 1.45;\n}\n\n.step[data-status=\"done\"] .marker {\n border-color: var(--jl-accent-line);\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n.step[data-status=\"done\"] .label {\n color: var(--jl-text);\n}\n\n.step[data-status=\"current\"] .marker {\n border-color: var(--jl-accent);\n background: var(--jl-accent);\n color: var(--jl-on-accent);\n box-shadow: 0 0 0 4px var(--jl-accent-soft);\n}\n\n.step[data-status=\"current\"] .label {\n color: var(--jl-accent);\n font-weight: 700;\n}\n\n.step[data-failed] .marker {\n border-color: color-mix(in srgb, var(--jl-danger) 40%, var(--jl-line));\n background: var(--jl-danger-soft);\n color: var(--jl-danger);\n box-shadow: none;\n}\n\n.step[data-failed] .label {\n color: var(--jl-danger);\n}\n\nbutton.head:hover .label {\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n\n.line {\n flex: 1;\n min-width: 24px;\n height: 1px;\n /* Further from the label before it than from the next marker: a label reads as its own step's. */\n margin: calc(var(--marker) / 2) 12px 0 20px;\n background: var(--jl-line-strong);\n}\n\n.step[data-status=\"done\"] .line {\n background: var(--jl-accent);\n}\n\n.step:last-child .line {\n display: none;\n}\n\n/* Vertical: the markers in a column joined by a rule, the text beside them. */\n:host([orientation=\"vertical\"]) ol {\n flex-direction: column;\n}\n\n:host([orientation=\"vertical\"]) .step {\n position: relative;\n flex: none;\n padding-bottom: 24px;\n}\n\n:host([orientation=\"vertical\"]) .step:last-child {\n padding-bottom: 0;\n}\n\n:host([orientation=\"vertical\"]) .line {\n position: absolute;\n top: calc(var(--marker) + 4px);\n bottom: 4px;\n left: calc(var(--marker) / 2 - 0.5px);\n width: 1px;\n height: auto;\n min-width: 0;\n margin: 0;\n}\n\n/* Narrow, the horizontal steps keep their markers and only the current step's text. */\n@container (width < 560px) {\n /* Out of sight, still read: the same rules as .sr-only. */\n :host(:not([orientation=\"vertical\"])) .step:not([data-status=\"current\"]) .text {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n }\n\n :host(:not([orientation=\"vertical\"])) .description {\n display: none;\n }\n\n :host(:not([orientation=\"vertical\"])) .line {\n min-width: 8px;\n margin: calc(var(--marker) / 2) 8px 0;\n }\n\n /* The current step takes three shares of the room, the others one, never less than their marker and line: the\n label never runs into the next step, and takes an ellipsis only when there is no room at all. */\n :host(:not([orientation=\"vertical\"])) .step:not([data-status=\"current\"]) {\n min-width: min-content;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] {\n flex: 3 1 0;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] .label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n :host(:not([orientation=\"vertical\"])) .step[data-status=\"current\"] .line {\n min-width: 24px;\n margin-left: 16px;\n }\n}\n";
|
|
3
3
|
export { jl_steps_default as default };
|
|
@@ -38,6 +38,8 @@ export declare class JlSteps extends JlElement {
|
|
|
38
38
|
templateCss(): string;
|
|
39
39
|
onConnect(): void;
|
|
40
40
|
private render;
|
|
41
|
+
/** A failed step's ×, a done one's check, or the step's number. */
|
|
42
|
+
private markerOf;
|
|
41
43
|
private step;
|
|
42
44
|
/** Goes back to a done step people picked, and says so. */
|
|
43
45
|
private goBackTo;
|
|
@@ -2,21 +2,28 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { clampedNumber, jsonOf, oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
+
import { jlText } from "../lib/texts.js";
|
|
5
6
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
7
|
import jl_steps_default from "./jl-steps.css_raw.js";
|
|
7
8
|
import { css } from "@jadis/core";
|
|
8
|
-
import { Check } from "lucide";
|
|
9
|
+
import { Check, X } from "lucide";
|
|
9
10
|
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
10
11
|
// src/molecules/jl-steps.tsx
|
|
11
|
-
registerIcons({
|
|
12
|
+
registerIcons({
|
|
13
|
+
check: Check,
|
|
14
|
+
x: X
|
|
15
|
+
});
|
|
12
16
|
var STEPS_ORIENTATIONS = ["horizontal", "vertical"];
|
|
13
17
|
var CHECK_SIZE = 14;
|
|
14
18
|
var MAX_STEPS = 100;
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
var STATUS_TEXTS = {
|
|
20
|
+
current: "stepCurrent",
|
|
21
|
+
done: "stepDone",
|
|
22
|
+
upcoming: null
|
|
23
|
+
};
|
|
24
|
+
var statusText = (status) => {
|
|
25
|
+
const key = STATUS_TEXTS[status];
|
|
26
|
+
return key === null ? "" : jlText(key);
|
|
20
27
|
};
|
|
21
28
|
var statusOf = (index, current) => {
|
|
22
29
|
if (index < current) return "done";
|
|
@@ -45,8 +52,8 @@ var JlSteps = class extends JlElement {
|
|
|
45
52
|
/** Done steps become buttons that go back to them. */
|
|
46
53
|
clickable = this.useChange(false, () => this.render(), { attribute: "clickable" });
|
|
47
54
|
/** The list's name for screen readers. */
|
|
48
|
-
label = this.useChange(
|
|
49
|
-
this._refs.list.setAttribute("aria-label", value ||
|
|
55
|
+
label = this.useChange(jlText("progress"), (value) => {
|
|
56
|
+
this._refs.list.setAttribute("aria-label", value || jlText("progress"));
|
|
50
57
|
}, { attribute: "label" });
|
|
51
58
|
_refs = this.useRefs((ref) => ({ list: ref("ol") }));
|
|
52
59
|
templateHtml() {
|
|
@@ -65,21 +72,29 @@ var JlSteps = class extends JlElement {
|
|
|
65
72
|
const current = this.current.get();
|
|
66
73
|
this._refs.list.replaceChildren(...this.items.get().map((item, index) => this.step(item, index, statusOf(index, current))));
|
|
67
74
|
}
|
|
75
|
+
/** A failed step's ×, a done one's check, or the step's number. */
|
|
76
|
+
markerOf(item, index, status) {
|
|
77
|
+
if (item.failed) return /* @__PURE__ */ jsx(JlIcon, {
|
|
78
|
+
name: "x",
|
|
79
|
+
size: CHECK_SIZE
|
|
80
|
+
});
|
|
81
|
+
return status === "done" ? /* @__PURE__ */ jsx(JlIcon, {
|
|
82
|
+
name: "check",
|
|
83
|
+
size: CHECK_SIZE
|
|
84
|
+
}) : String(index + 1);
|
|
85
|
+
}
|
|
68
86
|
step(item, index, status) {
|
|
69
87
|
const content = [/* @__PURE__ */ jsx("span", {
|
|
70
88
|
class: "marker",
|
|
71
89
|
"aria-hidden": "true",
|
|
72
|
-
children:
|
|
73
|
-
name: "check",
|
|
74
|
-
size: CHECK_SIZE
|
|
75
|
-
}) : String(index + 1)
|
|
90
|
+
children: this.markerOf(item, index, status)
|
|
76
91
|
}), /* @__PURE__ */ jsxs("span", {
|
|
77
92
|
class: "text",
|
|
78
93
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
79
94
|
class: "label",
|
|
80
95
|
children: [item.label, /* @__PURE__ */ jsx("span", {
|
|
81
96
|
class: "sr-only",
|
|
82
|
-
children:
|
|
97
|
+
children: item.failed ? jlText("failedStep") : statusText(status)
|
|
83
98
|
})]
|
|
84
99
|
}), item.description === void 0 ? "" : /* @__PURE__ */ jsx("span", {
|
|
85
100
|
class: "description",
|
|
@@ -90,6 +105,7 @@ var JlSteps = class extends JlElement {
|
|
|
90
105
|
return /* @__PURE__ */ jsxs("li", {
|
|
91
106
|
class: "step",
|
|
92
107
|
"data-status": status,
|
|
108
|
+
"data-failed": item.failed ? "" : void 0,
|
|
93
109
|
"aria-current": status === "current" ? "step" : void 0,
|
|
94
110
|
children: [canGoBack ? /* @__PURE__ */ jsx("button", {
|
|
95
111
|
type: "button",
|
|
@@ -6,6 +6,7 @@ import { JlIcon } from "../atoms/jl-icon.js";
|
|
|
6
6
|
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
7
7
|
import { firstIndex, lastIndex, stepIndex } from "../lib/roving.js";
|
|
8
8
|
import { moveIndicator } from "../lib/indicator.js";
|
|
9
|
+
import { watchSizes } from "../lib/resize.js";
|
|
9
10
|
import { JlTabPanel } from "./jl-tab-panel.js";
|
|
10
11
|
import jl_tabs_default from "./jl-tabs.css_raw.js";
|
|
11
12
|
import { css } from "@jadis/core";
|
|
@@ -55,7 +56,7 @@ var JlTabs = class extends JlElement {
|
|
|
55
56
|
label = this.useChange("", (value) => setOrRemove(this._refs.list, "aria-label", value), { attribute: "label" });
|
|
56
57
|
_observers = {
|
|
57
58
|
mutations: new MutationObserver((records) => this.onMutations(records)),
|
|
58
|
-
resize:
|
|
59
|
+
resize: watchSizes(() => this.placeIndicator())
|
|
59
60
|
};
|
|
60
61
|
_refs = this.useRefs((ref) => ({
|
|
61
62
|
indicator: ref(".indicator"),
|
|
@@ -4,6 +4,7 @@ import { clampedNumber, jsonOf, oneOf } from "../lib/attributes.js";
|
|
|
4
4
|
import { followAnchor } from "../lib/floating.js";
|
|
5
5
|
import { registerIcons } from "../lib/icons.js";
|
|
6
6
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
7
|
+
import { jlText } from "../lib/texts.js";
|
|
7
8
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
8
9
|
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
9
10
|
import { keepInView } from "../lib/keep-in-view.js";
|
|
@@ -18,7 +19,6 @@ registerIcons({ x: X });
|
|
|
18
19
|
var REMOVE_ICON_SIZE = 12;
|
|
19
20
|
var NONE = -1;
|
|
20
21
|
var PLACEMENT = "bottom-start";
|
|
21
|
-
var VALUE_MISSING = "Add at least one tag.";
|
|
22
22
|
var NO_LIMIT = 0;
|
|
23
23
|
var COMMA = ",";
|
|
24
24
|
var MAX_SUGGESTIONS = 8;
|
|
@@ -413,7 +413,7 @@ var JlTagInput = class extends JlFormControl {
|
|
|
413
413
|
}
|
|
414
414
|
renderValidity() {
|
|
415
415
|
if (this.required.get() && this.value.get().length === 0) {
|
|
416
|
-
this.internals.setValidity({ valueMissing: true },
|
|
416
|
+
this.internals.setValidity({ valueMissing: true }, jlText("addTag"), this._refs.native);
|
|
417
417
|
return;
|
|
418
418
|
}
|
|
419
419
|
this.internals.setValidity({});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-toast.css?raw
|
|
2
|
-
var jl_toast_default = ":host {\n display: block;\n /* Coloured as jl-alert is, from the same tokens: a toned toast is tinted, its border and icon in its tone. */\n --fg: var(--jl-text-2);\n --bg: var(--jl-surface);\n --border: var(--jl-line);\n --bar: var(--jl-brand);\n}\n\n:host([tone=\"ok\"]),\n:host([tone=\"warn\"]),\n:host([tone=\"danger\"]),\n:host([tone=\"info\"]) {\n --border: color-mix(in srgb, var(--fg) 24%, var(--bg));\n --bar: var(--fg);\n}\n\n:host([tone=\"ok\"]) {\n --fg: var(--jl-ok);\n --bg: var(--jl-ok-soft);\n}\n\n:host([tone=\"warn\"]) {\n --fg: var(--jl-warn);\n --bg: var(--jl-warn-soft);\n}\n\n:host([tone=\"danger\"]) {\n --fg: var(--jl-danger);\n --bg: var(--jl-danger-soft);\n}\n\n:host([tone=\"info\"]) {\n --fg: var(--jl-info);\n --bg: var(--jl-info-soft);\n}\n\n.toast {\n position: relative;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 12px 14px 16px;\n overflow: hidden;\n border: 1px solid var(--border);\n border-radius: var(--jl-radius-lg);\n background: var(--bg);\n color: var(--jl-text);\n font-size: var(--jl-font-md);\n line-height: 20px;\n box-shadow: var(--jl-shadow-lg);\n}\n\n.icon {\n margin-top: 1px;\n color: var(--fg);\n}\n\n.content {\n display: grid;\n flex: 1;\n gap: 2px;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.heading {\n font-weight: 650;\n}\n\n.text {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n}\n\n.heading[hidden] + .text {\n color: var(--jl-text-2);\n font-size: var(--jl-font-md);\n}\n\n.buttons {\n display: flex;\n flex: none;\n align-items: center;\n gap: 2px;\n margin: -5px -4px -5px 0;\n}\n\n.buttons:not(:has(jl-button:not([hidden]))) {\n display: none;\n}\n\n.close {\n --jl-accent: var(--fg);\n --jl-accent-soft: color-mix(in srgb, var(--fg) 12%, transparent);\n}\n\n.progress {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 2px;\n}\n\n.bar {\n height: 100%;\n background: var(--bar);\n transform-origin: left center;\n}\n\n:host([paused]) .bar {\n opacity: 0.55;\n}\n\n/* The line still counts the time, but does not move for people who asked for less motion. */\n@media (prefers-reduced-motion: reduce) {\n .progress {\n visibility: hidden;\n }\n}\n";
|
|
2
|
+
var jl_toast_default = ":host {\n display: block;\n /* Coloured as jl-alert is, from the same tokens: a toned toast is tinted, its border and icon in its tone. */\n --fg: var(--jl-text-2);\n --bg: var(--jl-surface);\n --border: var(--jl-line);\n --bar: var(--jl-brand);\n}\n\n:host([tone=\"ok\"]),\n:host([tone=\"warn\"]),\n:host([tone=\"danger\"]),\n:host([tone=\"info\"]) {\n --border: color-mix(in srgb, var(--fg) 24%, var(--bg));\n --bar: var(--fg);\n}\n\n:host([tone=\"ok\"]) {\n --fg: var(--jl-ok);\n --bg: var(--jl-ok-soft);\n}\n\n:host([tone=\"warn\"]) {\n --fg: var(--jl-warn);\n --bg: var(--jl-warn-soft);\n}\n\n:host([tone=\"danger\"]) {\n --fg: var(--jl-danger);\n --bg: var(--jl-danger-soft);\n}\n\n:host([tone=\"info\"]) {\n --fg: var(--jl-info);\n --bg: var(--jl-info-soft);\n}\n\n.toast {\n position: relative;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 12px 14px 16px;\n overflow: hidden;\n border: 1px solid var(--border);\n border-radius: var(--jl-radius-lg);\n background: var(--bg);\n color: var(--jl-text);\n font-size: var(--jl-font-md);\n line-height: 20px;\n box-shadow: var(--jl-shadow-lg);\n}\n\n.icon {\n margin-top: 1px;\n color: var(--fg);\n}\n\n.content {\n display: grid;\n flex: 1;\n gap: 2px;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.heading {\n font-weight: 650;\n}\n\n.text {\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n}\n\n.heading[hidden] + .text {\n color: var(--jl-text-2);\n font-size: var(--jl-font-md);\n}\n\n.buttons {\n display: flex;\n flex: none;\n align-items: center;\n gap: 2px;\n margin: -5px -4px -5px 0;\n}\n\n.buttons:not(:has(jl-button:not([hidden]))) {\n display: none;\n}\n\n.close {\n --jl-accent: var(--fg);\n --jl-accent-soft: color-mix(in srgb, var(--fg) 12%, transparent);\n}\n\n.work {\n margin-top: 8px;\n}\n\n.progress {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 2px;\n}\n\n.bar {\n height: 100%;\n background: var(--bar);\n transform-origin: left center;\n}\n\n:host([paused]) .bar {\n opacity: 0.55;\n}\n\n/* The line still counts the time, but does not move for people who asked for less motion. */\n@media (prefers-reduced-motion: reduce) {\n .progress {\n visibility: hidden;\n }\n}\n";
|
|
3
3
|
export { jl_toast_default as default };
|
|
@@ -4,7 +4,9 @@ export declare const TOAST_TONES: readonly ToastTone[];
|
|
|
4
4
|
/**
|
|
5
5
|
* One notification: a heading, a line of text, an icon in its tone's colour, and maybe an action such as "Undo".
|
|
6
6
|
* With a `duration` it closes by itself, a thin line showing the time left; hovering or focusing it pauses the
|
|
7
|
-
* line.
|
|
7
|
+
* line. While `working`, it shows the progress of the work it tells about (a download): `progress` percent, or a
|
|
8
|
+
* bar running back and forth without it. It emits `dismiss` once it has closed. Most pages call `toast()` rather
|
|
9
|
+
* than writing it.
|
|
8
10
|
*/
|
|
9
11
|
export declare class JlToast extends JlElement {
|
|
10
12
|
static readonly selector = "jl-toast";
|
|
@@ -44,6 +46,16 @@ export declare class JlToast extends JlElement {
|
|
|
44
46
|
get(): number;
|
|
45
47
|
set(setter: number | ((prevState: number) => number)): void;
|
|
46
48
|
}>>;
|
|
49
|
+
/** Shows a progress bar under the text, while the work it tells about runs. */
|
|
50
|
+
readonly working: Readonly<Readonly<{
|
|
51
|
+
get(): boolean;
|
|
52
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
53
|
+
}>>;
|
|
54
|
+
/** How far the work is, in percent; `null` (no attribute) for work of unknown length. */
|
|
55
|
+
readonly progress: Readonly<Readonly<{
|
|
56
|
+
get(): number | null;
|
|
57
|
+
set(setter: number | ((prevState: number | null) => number | null) | null): void;
|
|
58
|
+
}>>;
|
|
47
59
|
private readonly _timer;
|
|
48
60
|
private readonly _hold;
|
|
49
61
|
private readonly _refs;
|
|
@@ -3,8 +3,11 @@ import { JlElement } from "../base/jl-element.js";
|
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
5
|
import { TONE_ICONS, TONE_ICON_FILLED } from "../lib/options.js";
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
6
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
7
8
|
import { JlButton } from "../atoms/jl-button.js";
|
|
9
|
+
import { optionalNumber } from "../lib/progress.js";
|
|
10
|
+
import { JlProgress } from "../atoms/jl-progress.js";
|
|
8
11
|
import jl_toast_default from "./jl-toast.css_raw.js";
|
|
9
12
|
import { css } from "@jadis/core";
|
|
10
13
|
import { CircleCheck, CircleX, Info, Sparkles, TriangleAlert, X } from "lucide";
|
|
@@ -45,7 +48,9 @@ var prefersReducedMotion = () => window.matchMedia(REDUCED_MOTION).matches;
|
|
|
45
48
|
/**
|
|
46
49
|
* One notification: a heading, a line of text, an icon in its tone's colour, and maybe an action such as "Undo".
|
|
47
50
|
* With a `duration` it closes by itself, a thin line showing the time left; hovering or focusing it pauses the
|
|
48
|
-
* line.
|
|
51
|
+
* line. While `working`, it shows the progress of the work it tells about (a download): `progress` percent, or a
|
|
52
|
+
* bar running back and forth without it. It emits `dismiss` once it has closed. Most pages call `toast()` rather
|
|
53
|
+
* than writing it.
|
|
49
54
|
*/
|
|
50
55
|
var JlToast = class extends JlElement {
|
|
51
56
|
static selector = "jl-toast";
|
|
@@ -79,6 +84,15 @@ var JlToast = class extends JlElement {
|
|
|
79
84
|
}, { attribute: "action-label" });
|
|
80
85
|
/** How long it stays, in milliseconds; 0 keeps it until it is closed. */
|
|
81
86
|
duration = this.useChange(0, () => this.startTimer(), { attribute: "duration" });
|
|
87
|
+
/** Shows a progress bar under the text, while the work it tells about runs. */
|
|
88
|
+
working = this.useChange(false, (value) => {
|
|
89
|
+
this._refs.work.hidden = !value;
|
|
90
|
+
}, { attribute: "working" });
|
|
91
|
+
/** How far the work is, in percent; `null` (no attribute) for work of unknown length. */
|
|
92
|
+
progress = this.useChange(null, (value) => this._refs.work.value.set(value), {
|
|
93
|
+
attribute: "progress",
|
|
94
|
+
parse: optionalNumber
|
|
95
|
+
});
|
|
82
96
|
_timer = {
|
|
83
97
|
animation: null,
|
|
84
98
|
entered: false
|
|
@@ -95,7 +109,8 @@ var JlToast = class extends JlElement {
|
|
|
95
109
|
icon: ref(".icon"),
|
|
96
110
|
progress: ref(".progress"),
|
|
97
111
|
text: ref(".text"),
|
|
98
|
-
toast: ref(".toast")
|
|
112
|
+
toast: ref(".toast"),
|
|
113
|
+
work: ref(JlProgress)
|
|
99
114
|
}));
|
|
100
115
|
/** Closes the toast: it leaves, hides, then emits `dismiss`. */
|
|
101
116
|
dismiss() {
|
|
@@ -146,6 +161,11 @@ var JlToast = class extends JlElement {
|
|
|
146
161
|
class: "text",
|
|
147
162
|
hidden: true
|
|
148
163
|
}),
|
|
164
|
+
/* @__PURE__ */ jsx(JlProgress, {
|
|
165
|
+
class: "work",
|
|
166
|
+
size: "sm",
|
|
167
|
+
hidden: true
|
|
168
|
+
}),
|
|
149
169
|
/* @__PURE__ */ jsx("slot", {})
|
|
150
170
|
]
|
|
151
171
|
}),
|
|
@@ -161,7 +181,7 @@ var JlToast = class extends JlElement {
|
|
|
161
181
|
variant: "ghost",
|
|
162
182
|
size: "sm",
|
|
163
183
|
icon: "x",
|
|
164
|
-
hint: "
|
|
184
|
+
hint: jlText("close"),
|
|
165
185
|
hidden: true
|
|
166
186
|
})]
|
|
167
187
|
}),
|