@syware/jlib 0.5.1 → 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 +11 -4
- package/dist/atoms/jl-app-icon.css_raw.js +3 -0
- package/dist/atoms/jl-app-icon.d.ts +34 -0
- package/dist/atoms/jl-app-icon.js +86 -0
- package/dist/atoms/jl-avatar.js +1 -1
- package/dist/atoms/jl-badge.js +9 -2
- package/dist/atoms/jl-button.d.ts +5 -0
- package/dist/atoms/jl-button.js +5 -2
- package/dist/atoms/jl-chip.js +3 -2
- package/dist/atoms/jl-input.js +5 -4
- package/dist/atoms/jl-link.js +2 -2
- 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 +6 -5
- package/dist/atoms/jl-spinner.js +2 -2
- package/dist/base/jl-form-control.js +2 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -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 +12 -0
- package/dist/lib/text.js +16 -1
- package/dist/lib/texts.d.ts +97 -0
- package/dist/lib/texts.js +102 -0
- package/dist/lib/time.d.ts +5 -3
- package/dist/lib/time.js +23 -15
- package/dist/lib/tree.d.ts +10 -1
- package/dist/lib/tree.js +37 -3
- package/dist/lib/trigger.js +1 -1
- package/dist/molecules/jl-account-button.css_raw.js +1 -1
- package/dist/molecules/jl-account-button.d.ts +8 -1
- package/dist/molecules/jl-account-button.js +9 -2
- package/dist/molecules/jl-alert.js +3 -2
- package/dist/molecules/jl-breadcrumb.js +3 -3
- package/dist/molecules/jl-calendar.js +5 -5
- package/dist/molecules/jl-chip-group.js +3 -3
- 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 +6 -7
- package/dist/molecules/jl-copy-button.js +5 -4
- package/dist/molecules/jl-date-picker.js +7 -8
- package/dist/molecules/jl-empty.js +2 -2
- 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 +18 -15
- 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-list-item.js +1 -1
- 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.d.ts +4 -1
- package/dist/molecules/jl-load-state.js +20 -12
- package/dist/molecules/jl-menu.js +1 -1
- package/dist/molecules/jl-number-input.js +5 -5
- package/dist/molecules/jl-pagination.js +5 -5
- package/dist/molecules/jl-radio-group.js +2 -2
- package/dist/molecules/jl-search-button.js +5 -5
- package/dist/molecules/jl-search.js +5 -5
- package/dist/molecules/jl-segmented.js +3 -2
- 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 +3 -2
- package/dist/molecules/jl-tag-input.js +3 -3
- package/dist/molecules/jl-timeline.js +1 -1
- 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/molecules/jl-tooltip.d.ts +4 -1
- package/dist/molecules/jl-tooltip.js +27 -15
- 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 +40 -10
- package/dist/organisms/jl-confirm.d.ts +2 -1
- package/dist/organisms/jl-confirm.js +18 -12
- package/dist/organisms/jl-dialog.js +2 -1
- package/dist/organisms/jl-drawer.js +2 -1
- package/dist/organisms/jl-flow.js +13 -13
- 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 +71 -14
- package/dist/organisms/jl-tab-bar.js +3 -3
- 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 +36 -6
- package/dist/organisms/jl-toaster.css_raw.js +1 -1
- 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/styles/tokens.css_raw.js +1 -1
- package/dist/templates/jl-app-shell.css_raw.js +1 -1
- package/dist/templates/jl-app-shell.d.ts +16 -1
- package/dist/templates/jl-app-shell.js +42 -3
- package/dist/templates/jl-auth-layout.css_raw.js +3 -0
- package/dist/templates/jl-auth-layout.d.ts +35 -0
- package/dist/templates/jl-auth-layout.js +139 -0
- package/dist/templates/jl-page.css_raw.js +1 -1
- package/dist/templates/jl-page.js +3 -3
- package/dist/templates/jl-split-view.css_raw.js +1 -1
- package/dist/templates/jl-split-view.d.ts +21 -1
- package/dist/templates/jl-split-view.js +37 -4
- package/dist/tokens.css +2 -0
- 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-split-view.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
package/dist/lib/time.js
CHANGED
|
@@ -7,8 +7,7 @@ var HOUR_S = 3600;
|
|
|
7
7
|
var DAY_S = HOURS_PER_DAY * HOUR_S;
|
|
8
8
|
var NOW_UNDER_S = 45;
|
|
9
9
|
var MINUTES_UNDER_S = 2700;
|
|
10
|
-
var
|
|
11
|
-
var DAYS_UNDER_S = 7 * DAY_S;
|
|
10
|
+
var DAYS_UNDER = 7;
|
|
12
11
|
/** A number of one unit, as the language writes it short: "33 secs", "3 min", "2 Std.". */
|
|
13
12
|
var unitText = (value, unit, locale) => new Intl.NumberFormat(locale, {
|
|
14
13
|
maximumFractionDigits: 0,
|
|
@@ -27,34 +26,43 @@ function pair(first, second, locale) {
|
|
|
27
26
|
}
|
|
28
27
|
/**
|
|
29
28
|
* A duration in the units that read best: "< 1 sec" under a second (never "0.0 s"), then seconds, minutes, hours
|
|
30
|
-
* and minutes, days and hours.
|
|
29
|
+
* and minutes, days and hours. The unit is chosen once rounded: 59.6 seconds is "1 min", not "60 secs". Not a
|
|
30
|
+
* number gives "".
|
|
31
31
|
*/
|
|
32
32
|
function formatDuration(milliseconds, locale) {
|
|
33
|
+
if (!Number.isFinite(milliseconds)) return "";
|
|
33
34
|
const seconds = Math.max(0, milliseconds) / SECOND_MS;
|
|
34
35
|
if (seconds < 1) return `< ${unitText(1, "second", locale)}`;
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
36
|
+
const wholeSeconds = Math.round(seconds);
|
|
37
|
+
if (wholeSeconds < MINUTE_S) return unitText(wholeSeconds, "second", locale);
|
|
38
|
+
const minutes = Math.round(seconds / MINUTE_S);
|
|
39
|
+
if (minutes < MINUTES_PER_HOUR) return unitText(minutes, "minute", locale);
|
|
40
|
+
if (minutes < 1440) return pair([Math.floor(minutes / MINUTES_PER_HOUR), "hour"], [minutes % MINUTES_PER_HOUR, "minute"], locale);
|
|
41
41
|
const hours = Math.round(seconds / HOUR_S);
|
|
42
42
|
return pair([Math.floor(hours / HOURS_PER_DAY), "day"], [hours % HOURS_PER_DAY, "hour"], locale);
|
|
43
43
|
}
|
|
44
|
+
/** Midnight of a date's day, in the reader's time zone. */
|
|
45
|
+
var startOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
|
|
46
|
+
/** How many days on the calendar from `now` to `then`: -1 is yesterday, whatever the hours. */
|
|
47
|
+
var calendarDays = (then, now) => Math.round((startOfDay(then) - startOfDay(now)) / (DAY_S * SECOND_MS));
|
|
44
48
|
/**
|
|
45
|
-
* When something happened, from `now`: "now", "5 minutes ago", "3 hours ago", "yesterday"
|
|
46
|
-
* date ("12 Mar", with the year when it is not this year's). Times to
|
|
49
|
+
* When something happened, from `now`: "now", "5 minutes ago", "3 hours ago" the same day, "yesterday" or "3 days
|
|
50
|
+
* ago" by the calendar within a week, then the date ("12 Mar", with the year when it is not this year's). Times to
|
|
51
|
+
* come read the same way: "in 5 minutes". A date that is not one gives "".
|
|
47
52
|
*/
|
|
48
53
|
function formatRelativeTime(date, now, locale) {
|
|
49
54
|
const then = new Date(date);
|
|
50
|
-
const
|
|
55
|
+
const today = new Date(now);
|
|
56
|
+
if (Number.isNaN(then.getTime()) || Number.isNaN(today.getTime())) return "";
|
|
57
|
+
const seconds = (then.getTime() - today.getTime()) / SECOND_MS;
|
|
51
58
|
const distance = Math.abs(seconds);
|
|
52
59
|
const relative = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
53
60
|
if (distance < NOW_UNDER_S) return relative.format(0, "second");
|
|
54
61
|
if (distance < MINUTES_UNDER_S) return relative.format(Math.round(seconds / MINUTE_S), "minute");
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
62
|
+
const days = calendarDays(then, today);
|
|
63
|
+
if (days === 0) return relative.format(Math.round(seconds / HOUR_S), "hour");
|
|
64
|
+
if (Math.abs(days) < DAYS_UNDER) return relative.format(days, "day");
|
|
65
|
+
const sameYear = then.getFullYear() === today.getFullYear();
|
|
58
66
|
return new Intl.DateTimeFormat(locale, {
|
|
59
67
|
day: "numeric",
|
|
60
68
|
month: "short",
|
package/dist/lib/tree.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { TreeAction, TreeItem, VisibleTreeItem } from '../types/jl-tree.types';
|
|
2
|
-
/** An item with `children`, even empty, is a folder. */
|
|
2
|
+
/** An item with `children`, even empty, is a folder; so is a `lazy` one, whose children are not loaded yet. */
|
|
3
3
|
export declare const isFolder: (item: TreeItem) => boolean;
|
|
4
|
+
/** The items of a level: the roots when `parent` is null, otherwise that folder's children (none when unknown). */
|
|
5
|
+
export declare function childrenOf(items: readonly TreeItem[], parent: string | null): readonly TreeItem[];
|
|
6
|
+
/** The tree with a page of items added at the end of a level: the roots when `parent` is null. */
|
|
7
|
+
export declare function withPage(items: readonly TreeItem[], parent: string | null, page: readonly TreeItem[]): TreeItem[];
|
|
8
|
+
/**
|
|
9
|
+
* The tree with one more row at the end of the levels that have one (`extraRow` gives its id, or null): the row
|
|
10
|
+
* that loads a level's next page, or loads it again after an error. The keyboard then reaches it as an item.
|
|
11
|
+
*/
|
|
12
|
+
export declare function withExtraRows(items: readonly TreeItem[], extraRow: (parent: string | null) => string | null, parent?: string | null): TreeItem[];
|
|
4
13
|
/** The items a person sees, in order: the roots, and the children of every open folder, with their depth. */
|
|
5
14
|
export declare function visibleItems(items: readonly TreeItem[], expanded: ReadonlySet<string>, level?: number, parent?: string | null): VisibleTreeItem[];
|
|
6
15
|
/** Every item of the tree with its parent, open or not. */
|
package/dist/lib/tree.js
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
// src/lib/tree.ts
|
|
2
|
-
/** An item with `children`, even empty, is a folder. */
|
|
3
|
-
var isFolder = (item) => Array.isArray(item.children);
|
|
2
|
+
/** An item with `children`, even empty, is a folder; so is a `lazy` one, whose children are not loaded yet. */
|
|
3
|
+
var isFolder = (item) => Array.isArray(item.children) || item.lazy === true;
|
|
4
|
+
/** The items of a level: the roots when `parent` is null, otherwise that folder's children (none when unknown). */
|
|
5
|
+
function childrenOf(items, parent) {
|
|
6
|
+
if (parent === null) return items;
|
|
7
|
+
return allItems(items).find((entry) => entry.item.id === parent)?.item.children ?? [];
|
|
8
|
+
}
|
|
9
|
+
/** The tree with a page of items added at the end of a level: the roots when `parent` is null. */
|
|
10
|
+
function withPage(items, parent, page) {
|
|
11
|
+
if (parent === null) return [...items, ...page];
|
|
12
|
+
return items.map((item) => {
|
|
13
|
+
if (item.id === parent) return {
|
|
14
|
+
...item,
|
|
15
|
+
children: [...item.children ?? [], ...page]
|
|
16
|
+
};
|
|
17
|
+
return item.children === void 0 ? item : {
|
|
18
|
+
...item,
|
|
19
|
+
children: withPage(item.children, parent, page)
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The tree with one more row at the end of the levels that have one (`extraRow` gives its id, or null): the row
|
|
25
|
+
* that loads a level's next page, or loads it again after an error. The keyboard then reaches it as an item.
|
|
26
|
+
*/
|
|
27
|
+
function withExtraRows(items, extraRow, parent = null) {
|
|
28
|
+
const own = items.map((item) => isFolder(item) ? {
|
|
29
|
+
...item,
|
|
30
|
+
children: withExtraRows(item.children ?? [], extraRow, item.id)
|
|
31
|
+
} : item);
|
|
32
|
+
const extra = extraRow(parent);
|
|
33
|
+
return extra === null ? own : [...own, {
|
|
34
|
+
id: extra,
|
|
35
|
+
label: ""
|
|
36
|
+
}];
|
|
37
|
+
}
|
|
4
38
|
/** The items a person sees, in order: the roots, and the children of every open folder, with their depth. */
|
|
5
39
|
function visibleItems(items, expanded, level = 1, parent = null) {
|
|
6
40
|
return items.flatMap((item) => {
|
|
@@ -86,4 +120,4 @@ function treeKeyAction(items, expanded, focused, key) {
|
|
|
86
120
|
const index = visible.findIndex((entry) => entry.item.id === focused);
|
|
87
121
|
return handler(visible, Math.max(0, index), expanded);
|
|
88
122
|
}
|
|
89
|
-
export { allItems, isFolder, treeKeyAction, visibleItems, withExpanded };
|
|
123
|
+
export { allItems, childrenOf, isFolder, treeKeyAction, visibleItems, withExpanded, withExtraRows, withPage };
|
package/dist/lib/trigger.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/lib/trigger.ts
|
|
2
2
|
var NATIVE_FOCUSABLE = "a[href], button, input, select, textarea, summary, [tabindex]:not([tabindex=\"-1\"]), [contenteditable=\"true\"]";
|
|
3
|
-
var BASE_PART = "[part~=\"base\"]";
|
|
3
|
+
var BASE_PART = "[part~=\"base\"]:not([hidden])";
|
|
4
4
|
/**
|
|
5
5
|
* The element that carries a trigger's accessible state: the inner `base` part of a component (where its focus
|
|
6
6
|
* and its name are), or else the element itself.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-account-button.css?raw
|
|
2
|
-
var jl_account_button_default = ":host {\n display: block;\n}\n\n.base {\n display: flex;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-radius: var(--jl-radius-sm);\n background: transparent;\n color: var(--jl-text);\n text-align: left;\n text-decoration: none;\n cursor: pointer;\n transition: background var(--jl-fast) var(--jl-ease);\n}\n\n.base:hover {\n background: var(--jl-surface-2);\n}\n\n.content {\n display: flex;\n flex: 1;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n\njl-avatar {\n flex: none;\n}\n\n.text {\n display: grid;\n min-width: 0;\n line-height: 1.3;\n}\n\n.name,\n.description {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.name {\n font-size: var(--jl-font-sm);\n font-weight: 650;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n}\n\n/* The avatar alone, round. */\n:host([compact]) {\n display: inline-block;\n}\n\n:host([compact]) .base {\n width: auto;\n padding: 2px;\n border-radius: var(--jl-radius-pill);\n}\n\n:host([compact]) .text {\n display: none;\n}\n";
|
|
2
|
+
var jl_account_button_default = ":host {\n display: block;\n}\n\n.base {\n display: flex;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-radius: var(--jl-radius-sm);\n background: transparent;\n color: var(--jl-text);\n text-align: left;\n text-decoration: none;\n cursor: pointer;\n transition: background var(--jl-fast) var(--jl-ease);\n}\n\n.base:hover {\n background: var(--jl-surface-2);\n}\n\n.content {\n display: flex;\n flex: 1;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n\njl-avatar {\n flex: none;\n}\n\n.text {\n display: grid;\n min-width: 0;\n line-height: 1.3;\n}\n\n.name,\n.description {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.name {\n font-size: var(--jl-font-sm);\n font-weight: 650;\n}\n\n.description {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n}\n\n/* The avatar alone, round. */\n:host([compact]) {\n display: inline-block;\n}\n\n:host([compact]) .base {\n width: auto;\n padding: 2px;\n border-radius: var(--jl-radius-pill);\n}\n\n:host([compact]) .text {\n display: none;\n}\n\n/* Their account page is the one shown: marked as the side nav marks its current place. */\n\n:host([current]) .base {\n background: var(--jl-accent-soft);\n}\n\n:host([current]) .name {\n color: var(--jl-accent);\n}\n\n:host([current][compact]) .base {\n box-shadow: 0 0 0 2px var(--jl-accent);\n}\n";
|
|
3
3
|
export { jl_account_button_default as default };
|
|
@@ -2,7 +2,8 @@ import { JlElement } from '../base/jl-element';
|
|
|
2
2
|
/**
|
|
3
3
|
* The person signed in, where the frame of an app shows them (the foot of the side nav, a phone's top bar): their
|
|
4
4
|
* avatar, their name, and a line under it such as their role. With an `href` it is a link to their account, else a
|
|
5
|
-
* button that fires `press` (to open a menu). `compact` keeps the avatar alone, the name as its tooltip
|
|
5
|
+
* button that fires `press` (to open a menu). `compact` keeps the avatar alone, the name as its tooltip; `current`
|
|
6
|
+
* marks it while their account page is the one shown.
|
|
6
7
|
*/
|
|
7
8
|
export declare class JlAccountButton extends JlElement {
|
|
8
9
|
static readonly selector = "jl-account-button";
|
|
@@ -33,6 +34,11 @@ export declare class JlAccountButton extends JlElement {
|
|
|
33
34
|
get(): boolean;
|
|
34
35
|
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
35
36
|
}>>;
|
|
37
|
+
/** Their account page is the one shown: marked as the side nav marks its current place. */
|
|
38
|
+
readonly current: Readonly<Readonly<{
|
|
39
|
+
get(): boolean;
|
|
40
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
41
|
+
}>>;
|
|
36
42
|
private readonly _refs;
|
|
37
43
|
focus(options?: FocusOptions): void;
|
|
38
44
|
templateHtml(): Node;
|
|
@@ -41,6 +47,7 @@ export declare class JlAccountButton extends JlElement {
|
|
|
41
47
|
private control;
|
|
42
48
|
/** Moves the content into the link or back into the button. */
|
|
43
49
|
private renderLink;
|
|
50
|
+
private renderCurrent;
|
|
44
51
|
/** Its name for screen readers and its tooltip: the name, then the line under it. */
|
|
45
52
|
private renderLabel;
|
|
46
53
|
}
|
|
@@ -9,7 +9,8 @@ import { Fragment, jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
|
9
9
|
/**
|
|
10
10
|
* The person signed in, where the frame of an app shows them (the foot of the side nav, a phone's top bar): their
|
|
11
11
|
* avatar, their name, and a line under it such as their role. With an `href` it is a link to their account, else a
|
|
12
|
-
* button that fires `press` (to open a menu). `compact` keeps the avatar alone, the name as its tooltip
|
|
12
|
+
* button that fires `press` (to open a menu). `compact` keeps the avatar alone, the name as its tooltip; `current`
|
|
13
|
+
* marks it while their account page is the one shown.
|
|
13
14
|
*/
|
|
14
15
|
var JlAccountButton = class extends JlElement {
|
|
15
16
|
static selector = "jl-account-button";
|
|
@@ -31,8 +32,10 @@ var JlAccountButton = class extends JlElement {
|
|
|
31
32
|
href = this.useChange("", () => this.renderLink(), { attribute: "href" });
|
|
32
33
|
/** The avatar alone. */
|
|
33
34
|
compact = this.useChange(false, (value) => this.reflect("compact", value), { attribute: "compact" });
|
|
35
|
+
/** Their account page is the one shown: marked as the side nav marks its current place. */
|
|
36
|
+
current = this.useChange(false, (value) => this.renderCurrent(value), { attribute: "current" });
|
|
34
37
|
_refs = this.useRefs((ref) => ({
|
|
35
|
-
avatar: ref(
|
|
38
|
+
avatar: ref(JlAvatar),
|
|
36
39
|
button: ref("button"),
|
|
37
40
|
content: ref(".content"),
|
|
38
41
|
description: ref(".description"),
|
|
@@ -84,6 +87,10 @@ var JlAccountButton = class extends JlElement {
|
|
|
84
87
|
link.hidden = href === "";
|
|
85
88
|
setOrRemove(link, "href", href);
|
|
86
89
|
}
|
|
90
|
+
renderCurrent(current) {
|
|
91
|
+
this.reflect("current", current);
|
|
92
|
+
for (const control of [this._refs.button, this._refs.link]) setOrRemove(control, "aria-current", current ? "page" : "");
|
|
93
|
+
}
|
|
87
94
|
/** Its name for screen readers and its tooltip: the name, then the line under it. */
|
|
88
95
|
renderLabel() {
|
|
89
96
|
const label = [this.name.get(), this.description.get()].filter((part) => part !== "").join(", ");
|
|
@@ -3,8 +3,9 @@ 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 { TONES, TONE_ICONS, TONE_ICON_FILLED } from "../lib/options.js";
|
|
6
|
-
import {
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
7
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
8
|
+
import { hasSlotted } from "../lib/slots.js";
|
|
8
9
|
import { JlButton } from "../atoms/jl-button.js";
|
|
9
10
|
import jl_alert_default from "./jl-alert.css_raw.js";
|
|
10
11
|
import { css } from "@jadis/core";
|
|
@@ -115,7 +116,7 @@ var JlAlert = class extends JlElement {
|
|
|
115
116
|
class: "close",
|
|
116
117
|
variant: "ghost",
|
|
117
118
|
icon: "x",
|
|
118
|
-
hint: "
|
|
119
|
+
hint: jlText("dismiss"),
|
|
119
120
|
size: "sm",
|
|
120
121
|
hidden: true
|
|
121
122
|
})
|
|
@@ -2,6 +2,7 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf } 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_breadcrumb_default from "./jl-breadcrumb.css_raw.js";
|
|
7
8
|
import { css } from "@jadis/core";
|
|
@@ -14,7 +15,6 @@ registerIcons({
|
|
|
14
15
|
});
|
|
15
16
|
var ICON_SIZE = 15;
|
|
16
17
|
var SEPARATOR_SIZE = 14;
|
|
17
|
-
var DEFAULT_LABEL = "Breadcrumb";
|
|
18
18
|
var MIN_MAX = 2;
|
|
19
19
|
/** The crumbs shown: all of them, or the first, a gap for the middle, and the last `max - 1`. */
|
|
20
20
|
function visibleCrumbs(items, max, expanded) {
|
|
@@ -43,8 +43,8 @@ var JlBreadcrumb = class extends JlElement {
|
|
|
43
43
|
/** The most items shown before the middle folds; 0 never folds. */
|
|
44
44
|
max = this.useChange(0, () => this.render(), { attribute: "max" });
|
|
45
45
|
/** The trail's name for screen readers. */
|
|
46
|
-
label = this.useChange(
|
|
47
|
-
this._refs.nav.setAttribute("aria-label", value ||
|
|
46
|
+
label = this.useChange(jlText("breadcrumb"), (value) => {
|
|
47
|
+
this._refs.nav.setAttribute("aria-label", value || jlText("breadcrumb"));
|
|
48
48
|
}, { attribute: "label" });
|
|
49
49
|
_state = { expanded: false };
|
|
50
50
|
_refs = this.useRefs((ref) => ({
|
|
@@ -3,8 +3,9 @@ import { JlFormControl } from "../base/jl-form-control.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 {
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
7
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
8
|
+
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
8
9
|
import { addMonths, calendarDateOf, clampDate, dateAfterKey, dateFormatter, formatMonthTitle, isSameDate, isSameMonth, isWithin, monthGrid, monthHasDaysWithin, parseIsoDate, toIsoDate, weekdayNames } from "../lib/calendar.js";
|
|
9
10
|
import { pageLocale } from "../lib/locale.js";
|
|
10
11
|
import jl_calendar_default from "./jl-calendar.css_raw.js";
|
|
@@ -21,7 +22,6 @@ var MONDAY = 1;
|
|
|
21
22
|
var SUNDAY = 0;
|
|
22
23
|
var SATURDAY = 6;
|
|
23
24
|
var SELECT_KEYS = ["Enter", " "];
|
|
24
|
-
var VALUE_MISSING = "Choose a date.";
|
|
25
25
|
var FULL_DATE = { dateStyle: "full" };
|
|
26
26
|
/** The first day of the week from its attribute: 0 (Sunday) to 6 (Saturday), Monday when absent. */
|
|
27
27
|
var parseWeekday = (value) => Math.round(clampedNumber(MONDAY, SUNDAY, SATURDAY)(value));
|
|
@@ -95,7 +95,7 @@ var JlCalendar = class extends JlFormControl {
|
|
|
95
95
|
/* @__PURE__ */ jsx("button", {
|
|
96
96
|
class: "nav previous",
|
|
97
97
|
type: "button",
|
|
98
|
-
"aria-label": "
|
|
98
|
+
"aria-label": jlText("previousMonth"),
|
|
99
99
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
100
100
|
name: "chevron-left",
|
|
101
101
|
size: NAV_ICON_SIZE
|
|
@@ -109,7 +109,7 @@ var JlCalendar = class extends JlFormControl {
|
|
|
109
109
|
/* @__PURE__ */ jsx("button", {
|
|
110
110
|
class: "nav next",
|
|
111
111
|
type: "button",
|
|
112
|
-
"aria-label": "
|
|
112
|
+
"aria-label": jlText("nextMonth"),
|
|
113
113
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
114
114
|
name: "chevron-right",
|
|
115
115
|
size: NAV_ICON_SIZE
|
|
@@ -299,7 +299,7 @@ var JlCalendar = class extends JlFormControl {
|
|
|
299
299
|
}
|
|
300
300
|
renderValidity() {
|
|
301
301
|
if (this.required.get() && parseIsoDate(this.value.get()) === null) {
|
|
302
|
-
this.internals.setValidity({ valueMissing: true },
|
|
302
|
+
this.internals.setValidity({ valueMissing: true }, jlText("chooseDateMissing"));
|
|
303
303
|
return;
|
|
304
304
|
}
|
|
305
305
|
this.internals.setValidity({});
|
|
@@ -3,8 +3,9 @@ import { JlFormControl } from "../base/jl-form-control.js";
|
|
|
3
3
|
import { jsonOf, oneOf, stringList } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
5
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
-
import {
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
7
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
8
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
8
9
|
import { rovingIndex } from "../lib/roving-index.js";
|
|
9
10
|
import jl_chip_group_default from "./jl-chip-group.css_raw.js";
|
|
10
11
|
import { css } from "@jadis/core";
|
|
@@ -19,7 +20,6 @@ var ICON_SIZES = {
|
|
|
19
20
|
};
|
|
20
21
|
var SELECTED_ICON = "check";
|
|
21
22
|
var CHIP_SELECTOR = ".chip";
|
|
22
|
-
var VALUE_MISSING = "Please select one of these options.";
|
|
23
23
|
/** The keys that move between the chips; with one choice, the choice moves too, as with native radios. */
|
|
24
24
|
var MOVES = /* @__PURE__ */ new Map([
|
|
25
25
|
["ArrowDown", "next"],
|
|
@@ -252,7 +252,7 @@ var JlChipGroup = class extends JlFormControl {
|
|
|
252
252
|
this.internals.setValidity({});
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
255
|
-
this.internals.setValidity({ valueMissing: true },
|
|
255
|
+
this.internals.setValidity({ valueMissing: true }, jlText("selectOption"), this.chips()[0] ?? this._refs.group);
|
|
256
256
|
}
|
|
257
257
|
};
|
|
258
258
|
JlChipGroup.register();
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/molecules/jl-code-block.css?raw
|
|
2
|
-
var jl_code_block_default = ":host {\n display: block;\n min-width: 0;\n}\n\nfigure {\n position: relative;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius);\n background: var(--jl-surface-2);\n overflow: hidden;\n}\n\nheader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n height: 38px;\n padding: 0 52px 0 14px;\n border-bottom: 1px solid var(--jl-line);\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n}\n\n.heading {\n overflow: hidden;\n color: var(--jl-text-2);\n font-family: var(--jl-font-mono);\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.language {\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.body {\n display: flex;\n min-width: 0;\n}\n\n.gutter,\npre {\n padding: 14px 16px;\n font-family: var(--jl-font-mono);\n font-size: 12.5px;\n line-height: 1.7;\n font-variant-ligatures: no-contextual;\n}\n\n.gutter {\n flex: none;\n padding-right: 4px;\n color: var(--jl-faint);\n text-align: right;\n white-space: pre;\n user-select: none;\n}\n\npre {\n flex: 1;\n min-width: 0;\n margin: 0;\n padding-right: 48px;\n overflow-x: auto;\n color: var(--jl-text);\n tab-size: 2;\n}\n\n:host([wrap]) pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.copy {\n position: absolute;\n top: 6px;\n right: 6px;\n background: var(--jl-surface-2);\n border-radius: var(--jl-radius-sm);\n}\n\n:host(:not([has-header])) .copy {\n opacity: 0.6;\n transition: opacity var(--jl-fast) var(--jl-ease);\n}\n\n:host(:not([has-header])) figure:hover .copy,\n.copy:focus-within {\n opacity: 1;\n}\n\n.tok-comment {\n color: var(--jl-code-comment);\n font-style: italic;\n}\n\n.tok-string {\n color: var(--jl-code-string);\n}\n\n.tok-number {\n color: var(--jl-code-number);\n}\n\n.tok-keyword {\n color: var(--jl-code-keyword);\n}\n\n.tok-tag {\n color: var(--jl-code-tag);\n}\n\n.tok-attribute {\n color: var(--jl-code-attribute);\n}\n\n.tok-property {\n color: var(--jl-code-property);\n}\n\n.tok-function {\n color: var(--jl-code-function);\n}\n\n.tok-punctuation {\n color: var(--jl-muted);\n}\n";
|
|
2
|
+
var jl_code_block_default = ":host {\n display: block;\n min-width: 0;\n --max-height: none;\n}\n\nfigure {\n position: relative;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius);\n background: var(--jl-surface-2);\n overflow: hidden;\n}\n\nheader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n height: 38px;\n padding: 0 52px 0 14px;\n border-bottom: 1px solid var(--jl-line);\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n}\n\n.heading {\n overflow: hidden;\n color: var(--jl-text-2);\n font-family: var(--jl-font-mono);\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.language {\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.body {\n display: flex;\n min-width: 0;\n max-height: var(--max-height);\n overflow-y: auto;\n}\n\n.gutter,\npre {\n padding: 14px 16px;\n font-family: var(--jl-font-mono);\n font-size: 12.5px;\n line-height: 1.7;\n font-variant-ligatures: no-contextual;\n}\n\n.gutter {\n flex: none;\n padding-right: 4px;\n color: var(--jl-faint);\n text-align: right;\n white-space: pre;\n user-select: none;\n}\n\npre {\n flex: 1;\n min-width: 0;\n margin: 0;\n padding-right: 48px;\n overflow-x: auto;\n color: var(--jl-text);\n tab-size: 2;\n}\n\n:host([wrap]) pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.copy {\n position: absolute;\n top: 6px;\n right: 6px;\n background: var(--jl-surface-2);\n border-radius: var(--jl-radius-sm);\n}\n\n:host(:not([has-header])) .copy {\n opacity: 0.6;\n transition: opacity var(--jl-fast) var(--jl-ease);\n}\n\n:host(:not([has-header])) figure:hover .copy,\n.copy:focus-within {\n opacity: 1;\n}\n\n.tok-comment {\n color: var(--jl-code-comment);\n font-style: italic;\n}\n\n.tok-string {\n color: var(--jl-code-string);\n}\n\n.tok-number {\n color: var(--jl-code-number);\n}\n\n.tok-keyword {\n color: var(--jl-code-keyword);\n}\n\n.tok-tag {\n color: var(--jl-code-tag);\n}\n\n.tok-attribute {\n color: var(--jl-code-attribute);\n}\n\n.tok-property {\n color: var(--jl-code-property);\n}\n\n.tok-function {\n color: var(--jl-code-function);\n}\n\n.tok-punctuation {\n color: var(--jl-muted);\n}\n";
|
|
3
3
|
export { jl_code_block_default as default };
|
|
@@ -33,6 +33,11 @@ export declare class JlCodeBlock extends JlElement {
|
|
|
33
33
|
get(): boolean;
|
|
34
34
|
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
35
35
|
}>>;
|
|
36
|
+
/** A CSS height past which the code scrolls under its header: `320px`, `50vh`; a number is pixels. */
|
|
37
|
+
readonly maxHeight: Readonly<Readonly<{
|
|
38
|
+
get(): string;
|
|
39
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
40
|
+
}>>;
|
|
36
41
|
private readonly _refs;
|
|
37
42
|
templateHtml(): Node;
|
|
38
43
|
templateCss(): string;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
|
-
import { highlightedNodes } from "../lib/highlight.js";
|
|
5
4
|
import { dedent } from "../lib/text.js";
|
|
5
|
+
import { cssLength } from "../lib/css-length.js";
|
|
6
|
+
import { highlightedNodes } from "../lib/highlight.js";
|
|
6
7
|
import jl_code_block_default from "./jl-code-block.css_raw.js";
|
|
7
8
|
import { JlCopyButton } from "./jl-copy-button.js";
|
|
8
9
|
import { css } from "@jadis/core";
|
|
@@ -41,9 +42,11 @@ var JlCodeBlock = class extends JlElement {
|
|
|
41
42
|
}, { attribute: "hide-copy" });
|
|
42
43
|
/** Wraps long lines instead of scrolling sideways. */
|
|
43
44
|
wrap = this.useChange(false, (value) => this.reflect("wrap", value), { attribute: "wrap" });
|
|
45
|
+
/** A CSS height past which the code scrolls under its header: `320px`, `50vh`; a number is pixels. */
|
|
46
|
+
maxHeight = this.useChange("", (value) => this.style.setProperty("--max-height", value.trim() === "" ? "none" : cssLength(value)), { attribute: "max-height" });
|
|
44
47
|
_refs = this.useRefs((ref) => ({
|
|
45
48
|
code: ref("code"),
|
|
46
|
-
copy: ref(
|
|
49
|
+
copy: ref(JlCopyButton),
|
|
47
50
|
gutter: ref(".gutter"),
|
|
48
51
|
header: ref("header"),
|
|
49
52
|
heading: ref(".heading"),
|
|
@@ -4,8 +4,9 @@ import { 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 {
|
|
7
|
+
import { jlText } from "../lib/texts.js";
|
|
8
8
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
9
|
+
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
9
10
|
import { keepInView } from "../lib/keep-in-view.js";
|
|
10
11
|
import { edgeEnabledIndex, filterOptions, foldText, matchParts, nextEnabledIndex } from "../lib/option-filter.js";
|
|
11
12
|
import jl_combobox_default from "./jl-combobox.css_raw.js";
|
|
@@ -23,8 +24,6 @@ var ACTION_ICON_SIZE = 14;
|
|
|
23
24
|
var CHECK_SIZE = 14;
|
|
24
25
|
var NONE = -1;
|
|
25
26
|
var PLACEMENT = "bottom-start";
|
|
26
|
-
var VALUE_MISSING = "Choose an option.";
|
|
27
|
-
var DEFAULT_EMPTY_TEXT = "No results";
|
|
28
27
|
/** A JSON attribute that should hold a list of options; anything else gives none. */
|
|
29
28
|
var parseOptions = (value) => {
|
|
30
29
|
const parsed = jsonOf([])(value);
|
|
@@ -57,7 +56,7 @@ var JlCombobox = class extends JlFormControl {
|
|
|
57
56
|
/** Shows a button that empties the field while it holds text. */
|
|
58
57
|
clearable = this.useChange(false, () => this.renderClear(), { attribute: "clearable" });
|
|
59
58
|
/** What the list says when no option matches. */
|
|
60
|
-
emptyText = this.useChange(
|
|
59
|
+
emptyText = this.useChange(jlText("noResults"), (value) => {
|
|
61
60
|
this._refs.empty.textContent = value;
|
|
62
61
|
}, { attribute: "empty-text" });
|
|
63
62
|
required = this.useChange(false, (value) => {
|
|
@@ -112,7 +111,7 @@ var JlCombobox = class extends JlFormControl {
|
|
|
112
111
|
/* @__PURE__ */ jsx("button", {
|
|
113
112
|
class: "action clear",
|
|
114
113
|
type: "button",
|
|
115
|
-
"aria-label": "
|
|
114
|
+
"aria-label": jlText("clear"),
|
|
116
115
|
tabIndex: -1,
|
|
117
116
|
hidden: true,
|
|
118
117
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
@@ -123,7 +122,7 @@ var JlCombobox = class extends JlFormControl {
|
|
|
123
122
|
/* @__PURE__ */ jsx("button", {
|
|
124
123
|
class: "action toggle",
|
|
125
124
|
type: "button",
|
|
126
|
-
"aria-label": "
|
|
125
|
+
"aria-label": jlText("showOptions"),
|
|
127
126
|
tabIndex: -1,
|
|
128
127
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
129
128
|
name: "chevron-down",
|
|
@@ -429,7 +428,7 @@ var JlCombobox = class extends JlFormControl {
|
|
|
429
428
|
}
|
|
430
429
|
renderValidity() {
|
|
431
430
|
if (this.required.get() && this.value.get() === "") {
|
|
432
|
-
this.internals.setValidity({ valueMissing: true },
|
|
431
|
+
this.internals.setValidity({ valueMissing: true }, jlText("chooseOption"), this._refs.native);
|
|
433
432
|
return;
|
|
434
433
|
}
|
|
435
434
|
this.internals.setValidity({});
|
|
@@ -3,6 +3,7 @@ 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 { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
+
import { jlText } from "../lib/texts.js";
|
|
6
7
|
import { JlButton } from "../atoms/jl-button.js";
|
|
7
8
|
import jl_copy_button_default from "./jl-copy-button.css_raw.js";
|
|
8
9
|
import { css } from "@jadis/core";
|
|
@@ -28,12 +29,12 @@ var JlCopyButton = class extends JlElement {
|
|
|
28
29
|
parse: oneOf(CONTROL_SIZES, "sm")
|
|
29
30
|
});
|
|
30
31
|
_timer = { id: 0 };
|
|
31
|
-
_refs = this.useRefs((ref) => ({ button: ref(
|
|
32
|
+
_refs = this.useRefs((ref) => ({ button: ref(JlButton) }));
|
|
32
33
|
templateHtml() {
|
|
33
34
|
return /* @__PURE__ */ jsx(JlButton, {
|
|
34
35
|
variant: "ghost",
|
|
35
36
|
icon: COPY_ICON,
|
|
36
|
-
hint: "
|
|
37
|
+
hint: jlText("copy")
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
templateCss() {
|
|
@@ -55,12 +56,12 @@ var JlCopyButton = class extends JlElement {
|
|
|
55
56
|
confirm() {
|
|
56
57
|
const button = this._refs.button;
|
|
57
58
|
button.icon.set(DONE_ICON);
|
|
58
|
-
button.hint.set("
|
|
59
|
+
button.hint.set(jlText("copied"));
|
|
59
60
|
this.reflect("copied", true);
|
|
60
61
|
window.clearTimeout(this._timer.id);
|
|
61
62
|
this._timer.id = window.setTimeout(() => {
|
|
62
63
|
button.icon.set(COPY_ICON);
|
|
63
|
-
button.hint.set("
|
|
64
|
+
button.hint.set(jlText("copy"));
|
|
64
65
|
this.reflect("copied", false);
|
|
65
66
|
}, CONFIRM_MS);
|
|
66
67
|
}
|
|
@@ -4,8 +4,9 @@ import { clampedNumber, 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 {
|
|
7
|
+
import { jlText } from "../lib/texts.js";
|
|
8
8
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
9
|
+
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
9
10
|
import { NUMERIC_DATE, compareDates, dateOrder, datePattern, formatDate, isDateText, parseIsoDate, parseTypedDate, toIsoDate } from "../lib/calendar.js";
|
|
10
11
|
import { pageLocale } from "../lib/locale.js";
|
|
11
12
|
import { JlCalendar } from "./jl-calendar.js";
|
|
@@ -24,8 +25,6 @@ var PLACEMENT = "bottom-start";
|
|
|
24
25
|
var MONDAY = 1;
|
|
25
26
|
var SUNDAY = 0;
|
|
26
27
|
var SATURDAY = 6;
|
|
27
|
-
var VALUE_MISSING = "Choose a date.";
|
|
28
|
-
var DIALOG_LABEL = "Choose a date";
|
|
29
28
|
var parseWeekday = (value) => Math.round(clampedNumber(MONDAY, SUNDAY, SATURDAY)(value));
|
|
30
29
|
/**
|
|
31
30
|
* A field for a date: it shows the date in digits, in the `locale`'s order (`25.10.2026`, `10/25/2026`), and opens a
|
|
@@ -81,7 +80,7 @@ var JlDatePicker = class extends JlFormControl {
|
|
|
81
80
|
openOnPress: null
|
|
82
81
|
};
|
|
83
82
|
_refs = this.useRefs((ref) => ({
|
|
84
|
-
calendar: ref(
|
|
83
|
+
calendar: ref(JlCalendar),
|
|
85
84
|
clear: ref(".clear"),
|
|
86
85
|
control: ref(".control"),
|
|
87
86
|
native: ref("input"),
|
|
@@ -117,7 +116,7 @@ var JlDatePicker = class extends JlFormControl {
|
|
|
117
116
|
/* @__PURE__ */ jsx("button", {
|
|
118
117
|
class: "action clear",
|
|
119
118
|
type: "button",
|
|
120
|
-
"aria-label": "
|
|
119
|
+
"aria-label": jlText("clear"),
|
|
121
120
|
tabIndex: -1,
|
|
122
121
|
hidden: true,
|
|
123
122
|
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
@@ -128,7 +127,7 @@ var JlDatePicker = class extends JlFormControl {
|
|
|
128
127
|
/* @__PURE__ */ jsx("button", {
|
|
129
128
|
class: "action open",
|
|
130
129
|
type: "button",
|
|
131
|
-
"aria-label":
|
|
130
|
+
"aria-label": jlText("chooseDate"),
|
|
132
131
|
"aria-haspopup": "dialog",
|
|
133
132
|
"aria-expanded": "false",
|
|
134
133
|
"aria-controls": this._popupId,
|
|
@@ -143,7 +142,7 @@ var JlDatePicker = class extends JlFormControl {
|
|
|
143
142
|
id: this._popupId,
|
|
144
143
|
popover: "auto",
|
|
145
144
|
role: "dialog",
|
|
146
|
-
"aria-label":
|
|
145
|
+
"aria-label": jlText("chooseDate"),
|
|
147
146
|
attrs: { part: "popup" },
|
|
148
147
|
children: /* @__PURE__ */ jsx(JlCalendar, { class: "calendar" })
|
|
149
148
|
})] });
|
|
@@ -314,7 +313,7 @@ var JlDatePicker = class extends JlFormControl {
|
|
|
314
313
|
}
|
|
315
314
|
renderMissing(anchor) {
|
|
316
315
|
if (this.required.get()) {
|
|
317
|
-
this.internals.setValidity({ valueMissing: true },
|
|
316
|
+
this.internals.setValidity({ valueMissing: true }, jlText("chooseDateMissing"), anchor);
|
|
318
317
|
return;
|
|
319
318
|
}
|
|
320
319
|
this.internals.setValidity({});
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
-
import { hasSlotted } from "../lib/slots.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { hasSlotted } from "../lib/slots.js";
|
|
7
7
|
import jl_empty_default from "./jl-empty.css_raw.js";
|
|
8
8
|
import { css } from "@jadis/core";
|
|
9
9
|
import { Inbox } from "lucide";
|
|
@@ -43,7 +43,7 @@ var JlEmpty = class extends JlElement {
|
|
|
43
43
|
actions: ref(".actions"),
|
|
44
44
|
description: ref(".description"),
|
|
45
45
|
heading: ref(".heading"),
|
|
46
|
-
icon: ref(
|
|
46
|
+
icon: ref(JlIcon),
|
|
47
47
|
medallion: ref(".medallion"),
|
|
48
48
|
slot: ref("slot")
|
|
49
49
|
}));
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/molecules/jl-facts.css?raw
|
|
2
|
+
var jl_facts_default = ":host {\n display: block;\n container-type: inline-size;\n}\n\n:host([empty]) {\n display: none;\n}\n\n.facts {\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr);\n gap: 6px 24px;\n margin: 0;\n font-size: var(--jl-font-md);\n}\n\n/* Each pair is a row of the grid: the labels line up in one column, the values in the other. */\n.fact {\n display: contents;\n}\n\ndt {\n color: var(--jl-muted);\n}\n\ndd {\n min-width: 0;\n margin: 0;\n color: var(--jl-text);\n overflow-wrap: anywhere;\n}\n\ncode {\n font-family: var(--jl-font-mono);\n font-size: var(--jl-font-sm);\n word-break: break-all;\n}\n\na {\n color: var(--jl-accent);\n text-decoration: none;\n}\n\na:hover {\n color: var(--jl-accent-strong);\n text-decoration: underline;\n}\n\n:host([orientation=\"vertical\"]) .facts {\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 180px), 1fr));\n gap: 16px 24px;\n}\n\n:host([orientation=\"vertical\"]) .fact {\n display: grid;\n gap: 2px;\n align-content: start;\n}\n\n@container (width < 420px) {\n .facts {\n grid-template-columns: minmax(0, 1fr);\n gap: 12px;\n }\n\n .fact {\n display: grid;\n gap: 2px;\n }\n}\n";
|
|
3
|
+
export { jl_facts_default as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
import type { Fact, FactRenderer, FactsOrientation } from '../types/jl-facts.types';
|
|
3
|
+
export declare const FACTS_ORIENTATIONS: readonly FactsOrientation[];
|
|
4
|
+
/**
|
|
5
|
+
* The facts about one thing, label and value: an object's size and digest, an order's customer and date. Facts
|
|
6
|
+
* without a value are left out, and an element with none takes no room. Values can be code (monospace, broken
|
|
7
|
+
* anywhere), links, or drawn by code (`renderers`, by a fact's `key`). Narrower than 420 pixels, labels go over
|
|
8
|
+
* their values.
|
|
9
|
+
*/
|
|
10
|
+
export declare class JlFacts extends JlElement {
|
|
11
|
+
static readonly selector = "jl-facts";
|
|
12
|
+
readonly items: Readonly<Readonly<{
|
|
13
|
+
get(): Fact[];
|
|
14
|
+
set(setter: Fact[] | ((prevState: Fact[]) => Fact[])): void;
|
|
15
|
+
}>>;
|
|
16
|
+
readonly orientation: Readonly<Readonly<{
|
|
17
|
+
get(): FactsOrientation;
|
|
18
|
+
set(setter: ((prevState: FactsOrientation) => FactsOrientation) | FactsOrientation): void;
|
|
19
|
+
}>>;
|
|
20
|
+
/** Draws the values of some facts by code, by their `key`: `{ type: (fact) => <JlBadge label={…} /> }`. */
|
|
21
|
+
readonly renderers: Readonly<Readonly<{
|
|
22
|
+
get(): Record<string, FactRenderer>;
|
|
23
|
+
set(setter: Record<string, FactRenderer> | ((prevState: Record<string, FactRenderer>) => Record<string, FactRenderer>)): void;
|
|
24
|
+
}>>;
|
|
25
|
+
/** The list's name for screen readers. */
|
|
26
|
+
readonly label: Readonly<Readonly<{
|
|
27
|
+
get(): string;
|
|
28
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
29
|
+
}>>;
|
|
30
|
+
private readonly _refs;
|
|
31
|
+
templateHtml(): Node;
|
|
32
|
+
templateCss(): string;
|
|
33
|
+
private render;
|
|
34
|
+
private valueNode;
|
|
35
|
+
}
|