@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
package/dist/lib/icons.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CircleAlert, createElement } from "lucide";
|
|
2
2
|
// src/lib/icons.ts
|
|
3
3
|
var FALLBACK = CircleAlert;
|
|
4
|
-
|
|
4
|
+
/** The width of every glyph's strokes, on lucide's 24-unit grid. */
|
|
5
|
+
var ICON_STROKE_WIDTH = 1.9;
|
|
5
6
|
/**
|
|
6
7
|
* The icons `jl-icon` can draw, by name. It starts empty: each component registers the icons it draws itself, and
|
|
7
8
|
* a page registers the names it writes, so a bundle holds only the icons in use.
|
|
@@ -27,13 +28,15 @@ function missing(name) {
|
|
|
27
28
|
}
|
|
28
29
|
return FALLBACK;
|
|
29
30
|
}
|
|
31
|
+
/** An icon's shapes, by its name; a name nobody registered gives a neutral mark instead of nothing. */
|
|
32
|
+
var iconNode = (name) => registry.get(name) ?? missing(name);
|
|
30
33
|
/** An icon as an SVG element; a name nobody registered draws a neutral mark instead of nothing. */
|
|
31
34
|
function iconElement(name, size) {
|
|
32
|
-
return createElement(
|
|
35
|
+
return createElement(iconNode(name), {
|
|
33
36
|
"aria-hidden": "true",
|
|
34
37
|
height: size,
|
|
35
|
-
"stroke-width":
|
|
38
|
+
"stroke-width": ICON_STROKE_WIDTH,
|
|
36
39
|
width: size
|
|
37
40
|
});
|
|
38
41
|
}
|
|
39
|
-
export { hasIcon, iconElement, iconNames, registerIcons };
|
|
42
|
+
export { ICON_STROKE_WIDTH, hasIcon, iconElement, iconNames, iconNode, registerIcons };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The rows shown: the values, or one empty row to type the first one in. */
|
|
2
|
+
export declare const rowsOf: (values: readonly string[]) => string[];
|
|
3
|
+
/** The rows with the one at `index` changed. */
|
|
4
|
+
export declare const withRowAt: (rows: readonly string[], index: number, value: string) => string[];
|
|
5
|
+
/** The rows without the one at `index`; one empty row stays when it was the last. */
|
|
6
|
+
export declare const withoutRowAt: (rows: readonly string[], index: number) => string[];
|
|
7
|
+
/** The values kept: the rows people filled in. */
|
|
8
|
+
export declare const filledValues: (rows: readonly string[]) => string[];
|
|
9
|
+
/** Whether another row fits under `max`; none or zero means no limit. */
|
|
10
|
+
export declare const canAddRow: (count: number, max: number) => boolean;
|
|
11
|
+
/** Whether two lists hold the same values in the same order. */
|
|
12
|
+
export declare const sameValues: (left: readonly string[], right: readonly string[]) => boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/lib/input-list.ts
|
|
2
|
+
/** The rows shown: the values, or one empty row to type the first one in. */
|
|
3
|
+
var rowsOf = (values) => values.length === 0 ? [""] : [...values];
|
|
4
|
+
/** The rows with the one at `index` changed. */
|
|
5
|
+
var withRowAt = (rows, index, value) => rows.map((row, at) => at === index ? value : row);
|
|
6
|
+
/** The rows without the one at `index`; one empty row stays when it was the last. */
|
|
7
|
+
var withoutRowAt = (rows, index) => rowsOf(rows.filter((_, at) => at !== index));
|
|
8
|
+
/** The values kept: the rows people filled in. */
|
|
9
|
+
var filledValues = (rows) => rows.filter((row) => row.trim() !== "");
|
|
10
|
+
/** Whether another row fits under `max`; none or zero means no limit. */
|
|
11
|
+
var canAddRow = (count, max) => max <= 0 || count < max;
|
|
12
|
+
/** Whether two lists hold the same values in the same order. */
|
|
13
|
+
var sameValues = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);
|
|
14
|
+
export { canAddRow, filledValues, rowsOf, sameValues, withRowAt, withoutRowAt };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The internals of a form-associated element. Where the DOM gives them no form methods (jsdom), they get ones that
|
|
3
|
+
* keep nothing and find every value valid; a browser's are left as they are.
|
|
4
|
+
*/
|
|
5
|
+
export declare function formInternals(element: HTMLElement): ElementInternals;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/lib/internals.ts
|
|
2
|
+
/** What a form control asks of its internals that jsdom's lack: with them, a page's unit tests can create it. */
|
|
3
|
+
var FORM_METHODS = {
|
|
4
|
+
checkValidity: () => true,
|
|
5
|
+
reportValidity: () => true,
|
|
6
|
+
setFormValue: () => void 0,
|
|
7
|
+
setValidity: () => void 0
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The internals of a form-associated element. Where the DOM gives them no form methods (jsdom), they get ones that
|
|
11
|
+
* keep nothing and find every value valid; a browser's are left as they are.
|
|
12
|
+
*/
|
|
13
|
+
function formInternals(element) {
|
|
14
|
+
const internals = element.attachInternals();
|
|
15
|
+
if (typeof internals.setFormValue === "function") return internals;
|
|
16
|
+
return Object.assign(internals, FORM_METHODS);
|
|
17
|
+
}
|
|
18
|
+
export { formInternals };
|
package/dist/lib/palette.js
CHANGED
|
@@ -3,12 +3,18 @@ import { fuzzyMatch } from "./fuzzy.js";
|
|
|
3
3
|
/** A match on a keyword counts less than one on the label people read. */
|
|
4
4
|
var KEYWORD_WEIGHT = .5;
|
|
5
5
|
var NO_GROUP = "";
|
|
6
|
+
var RESULT_SCORE = 0;
|
|
6
7
|
function keywordScore(query, keywords) {
|
|
7
8
|
const scores = keywords.map((keyword) => fuzzyMatch(query, keyword)?.score).filter((score) => score !== void 0);
|
|
8
9
|
return scores.length === 0 ? null : Math.max(...scores) * KEYWORD_WEIGHT;
|
|
9
10
|
}
|
|
10
11
|
function matchCommand(query, command) {
|
|
11
12
|
const label = fuzzyMatch(query, command.label);
|
|
13
|
+
if (command.result === true) return {
|
|
14
|
+
command,
|
|
15
|
+
positions: label?.positions ?? [],
|
|
16
|
+
score: RESULT_SCORE
|
|
17
|
+
};
|
|
12
18
|
const keyword = keywordScore(query, command.keywords ?? []);
|
|
13
19
|
if (label === null && keyword === null) return null;
|
|
14
20
|
if (label === null) return {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/lib/resize.ts
|
|
2
|
+
/** A stand-in that watches nothing, for a DOM without ResizeObserver (jsdom, which has no layout either). */
|
|
3
|
+
var INERT_OBSERVER = {
|
|
4
|
+
disconnect: () => void 0,
|
|
5
|
+
observe: () => void 0,
|
|
6
|
+
unobserve: () => void 0
|
|
7
|
+
};
|
|
8
|
+
/** Watches elements' sizes; where the DOM has no ResizeObserver, nothing changes size and nothing is watched. */
|
|
9
|
+
var watchSizes = (callback) => typeof ResizeObserver === "function" ? new ResizeObserver(callback) : INERT_OBSERVER;
|
|
10
|
+
export { watchSizes };
|
package/dist/lib/table.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TableAlign, TableCellFormat, TableColumn, TableRow, TableRowKey, TableSelectionState, TableSortDirection } from '../types/jl-table.types';
|
|
1
|
+
import type { TableAlign, TableCellFormat, TableCellRenderer, TableColumn, TableRow, TableRowKey, TableSelectionState, TableSortDirection } from '../types/jl-table.types';
|
|
2
2
|
export declare const nextSortDirection: (direction: TableSortDirection) => TableSortDirection;
|
|
3
3
|
/** A cell's value as a number, `NaN` when it is not one. */
|
|
4
4
|
export declare function toNumber(value: unknown): number;
|
|
@@ -28,3 +28,8 @@ export declare function selectionState(keys: readonly TableRowKey[], selected: R
|
|
|
28
28
|
export declare function toggleAll(keys: readonly TableRowKey[], selected: ReadonlySet<TableRowKey>): TableRowKey[];
|
|
29
29
|
/** The selection with one row added or taken out. */
|
|
30
30
|
export declare function toggleKey(selected: readonly TableRowKey[], key: TableRowKey, on: boolean): TableRowKey[];
|
|
31
|
+
/**
|
|
32
|
+
* A renderer of `renderers` written for the page's own type of row: the table hands each renderer back a row the
|
|
33
|
+
* page gave it, so `cellOf<Order>((order) => <JlLink href={order.href} label={order.name} />)` reads it typed.
|
|
34
|
+
*/
|
|
35
|
+
export declare const cellOf: <Row>(draw: (row: Row) => Node) => TableCellRenderer;
|
package/dist/lib/table.js
CHANGED
|
@@ -11,6 +11,10 @@ var DIRECTION_SIGN = {
|
|
|
11
11
|
none: 0
|
|
12
12
|
};
|
|
13
13
|
var DATE_FORMAT = { dateStyle: "medium" };
|
|
14
|
+
var DATE_TIME_FORMAT = {
|
|
15
|
+
dateStyle: "medium",
|
|
16
|
+
timeStyle: "short"
|
|
17
|
+
};
|
|
14
18
|
var nextSortDirection = (direction) => NEXT_DIRECTION[direction];
|
|
15
19
|
var isEmpty = (value) => value === null || value === void 0 || value === "";
|
|
16
20
|
/** A cell's value as a number, `NaN` when it is not one. */
|
|
@@ -31,6 +35,7 @@ var COMPARERS = {
|
|
|
31
35
|
badge: (a, b, locale) => String(a).localeCompare(String(b), locale),
|
|
32
36
|
code: (a, b, locale) => String(a).localeCompare(String(b), locale),
|
|
33
37
|
date: (a, b) => compareNumbers(toTime(a), toTime(b)),
|
|
38
|
+
datetime: (a, b) => compareNumbers(toTime(a), toTime(b)),
|
|
34
39
|
number: (a, b) => compareNumbers(toNumber(a), toNumber(b)),
|
|
35
40
|
text: (a, b, locale) => String(a).localeCompare(String(b), locale, { numeric: true })
|
|
36
41
|
};
|
|
@@ -41,6 +46,7 @@ function isUnorderable(value, format) {
|
|
|
41
46
|
badge: () => false,
|
|
42
47
|
code: () => false,
|
|
43
48
|
date: () => Number.isNaN(toTime(value)),
|
|
49
|
+
datetime: () => Number.isNaN(toTime(value)),
|
|
44
50
|
number: () => Number.isNaN(toNumber(value)),
|
|
45
51
|
text: () => false
|
|
46
52
|
}[format]();
|
|
@@ -66,6 +72,10 @@ var FORMATTERS = {
|
|
|
66
72
|
const time = toTime(value);
|
|
67
73
|
return Number.isNaN(time) ? String(value) : new Intl.DateTimeFormat(locale, DATE_FORMAT).format(time);
|
|
68
74
|
},
|
|
75
|
+
datetime: (value, locale) => {
|
|
76
|
+
const time = toTime(value);
|
|
77
|
+
return Number.isNaN(time) ? String(value) : new Intl.DateTimeFormat(locale, DATE_TIME_FORMAT).format(time);
|
|
78
|
+
},
|
|
69
79
|
number: (value, locale) => {
|
|
70
80
|
const number = toNumber(value);
|
|
71
81
|
return Number.isNaN(number) ? String(value) : new Intl.NumberFormat(locale).format(number);
|
|
@@ -107,4 +117,9 @@ function toggleKey(selected, key, on) {
|
|
|
107
117
|
const without = selected.filter((candidate) => candidate !== key);
|
|
108
118
|
return on ? [...without, key] : without;
|
|
109
119
|
}
|
|
110
|
-
|
|
120
|
+
/**
|
|
121
|
+
* A renderer of `renderers` written for the page's own type of row: the table hands each renderer back a row the
|
|
122
|
+
* page gave it, so `cellOf<Order>((order) => <JlLink href={order.href} label={order.name} />)` reads it typed.
|
|
123
|
+
*/
|
|
124
|
+
var cellOf = (draw) => (row) => draw(row);
|
|
125
|
+
export { cellOf, columnAlign, columnWidth, formatCell, nextSortDirection, rowKeyOf, selectionState, sortRows, toNumber, toTime, toggleAll, toggleKey };
|
package/dist/lib/text.d.ts
CHANGED
|
@@ -13,3 +13,5 @@ export type StarredPart = {
|
|
|
13
13
|
* A lone asterisk stays as it is; empty runs are left out.
|
|
14
14
|
*/
|
|
15
15
|
export declare function starredParts(text: string): StarredPart[];
|
|
16
|
+
/** A text with its `{placeholders}` filled; one without a value stays as it is. */
|
|
17
|
+
export declare const fillText: (template: string, values: Readonly<Record<string, string>>) => string;
|
package/dist/lib/text.js
CHANGED
|
@@ -22,4 +22,7 @@ function starredParts(text) {
|
|
|
22
22
|
text: piece
|
|
23
23
|
})).filter((part) => part.text !== "");
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
var PLACEHOLDER = /\{(\w+)\}/g;
|
|
26
|
+
/** A text with its `{placeholders}` filled; one without a value stays as it is. */
|
|
27
|
+
var fillText = (template, values) => template.replace(PLACEHOLDER, (whole, key) => values[key] ?? whole);
|
|
28
|
+
export { dedent, fillText, starredParts };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { JlTextKey, JlTexts } from '../types/texts.types';
|
|
2
|
+
/**
|
|
3
|
+
* Every text jlib's components show or say on their own, in English: labels for screen readers, buttons, states,
|
|
4
|
+
* the defaults of their text inputs. `{placeholders}` are filled when the text is shown.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_TEXTS: {
|
|
7
|
+
readonly addTag: 'Add at least one tag.';
|
|
8
|
+
readonly addValue: 'Add a value';
|
|
9
|
+
readonly back: 'Back';
|
|
10
|
+
readonly breadcrumb: 'Breadcrumb';
|
|
11
|
+
readonly browse: 'Browse';
|
|
12
|
+
readonly chooseDate: 'Choose a date';
|
|
13
|
+
readonly chooseDateMissing: 'Choose a date.';
|
|
14
|
+
readonly chooseFile: 'Choose a file.';
|
|
15
|
+
readonly chooseOption: 'Choose an option.';
|
|
16
|
+
readonly chooseRating: 'Choose a rating.';
|
|
17
|
+
readonly chosenFiles: 'Chosen files';
|
|
18
|
+
readonly clear: 'Clear';
|
|
19
|
+
readonly clearSearch: 'Clear the search';
|
|
20
|
+
readonly close: 'Close';
|
|
21
|
+
readonly closeMenu: 'Close the menu';
|
|
22
|
+
readonly collapseMenu: 'Collapse the menu';
|
|
23
|
+
readonly commandPalette: 'Command palette';
|
|
24
|
+
readonly commandPlaceholder: 'Type a command or search…';
|
|
25
|
+
readonly commands: 'Commands';
|
|
26
|
+
readonly copied: 'Copied';
|
|
27
|
+
readonly copy: 'Copy';
|
|
28
|
+
readonly decrease: 'Decrease';
|
|
29
|
+
readonly dismiss: 'Dismiss';
|
|
30
|
+
readonly downloadCancel: 'Cancel';
|
|
31
|
+
readonly downloadFailed: 'Not downloaded: {error}';
|
|
32
|
+
readonly downloadPreparing: 'Preparing the file… {time}';
|
|
33
|
+
readonly downloadReceived: '{received} received';
|
|
34
|
+
readonly downloadReceivedOf: '{received} of {total}';
|
|
35
|
+
readonly downloadSaved: 'Saved as {name}, {size}';
|
|
36
|
+
readonly dragToConnect: 'Drag to another node to connect';
|
|
37
|
+
readonly dropFile: 'Drop a file here';
|
|
38
|
+
readonly dropFiles: 'Drop files here';
|
|
39
|
+
readonly expandMenu: 'Expand the menu';
|
|
40
|
+
readonly failedStep: ', failed';
|
|
41
|
+
readonly fileTooLarge: 'is larger than {size}';
|
|
42
|
+
readonly fileTooMany: 'is one too many: the field takes a single file';
|
|
43
|
+
readonly fileUpTo: 'up to {size}';
|
|
44
|
+
readonly fileWrongType: 'is not an accepted type ({types})';
|
|
45
|
+
readonly fillField: 'Please fill in this field.';
|
|
46
|
+
readonly fitView: 'Show every node';
|
|
47
|
+
readonly flow: 'Flow';
|
|
48
|
+
readonly hidePassword: 'Hide the password';
|
|
49
|
+
readonly increase: 'Increase';
|
|
50
|
+
readonly leave: 'Leave';
|
|
51
|
+
readonly leaveText: 'Your changes are lost.';
|
|
52
|
+
readonly loadError: 'This could not be loaded.';
|
|
53
|
+
readonly loading: 'Loading';
|
|
54
|
+
readonly loadingMore: 'Loading…';
|
|
55
|
+
readonly loadStateError: 'Check the connection, then try again. Nothing was changed.';
|
|
56
|
+
readonly mainNavigation: 'Main';
|
|
57
|
+
readonly menu: 'Menu';
|
|
58
|
+
readonly navigation: 'Navigation';
|
|
59
|
+
readonly nextMonth: 'Next month';
|
|
60
|
+
readonly nextPage: 'Next page';
|
|
61
|
+
readonly noCommands: 'No matching commands';
|
|
62
|
+
readonly noData: 'No data';
|
|
63
|
+
readonly noResults: 'No results';
|
|
64
|
+
readonly notifications: 'Notifications';
|
|
65
|
+
readonly pagination: 'Pagination';
|
|
66
|
+
readonly previousMonth: 'Previous month';
|
|
67
|
+
readonly previousPage: 'Previous page';
|
|
68
|
+
readonly progress: 'Progress';
|
|
69
|
+
readonly rating: 'Rating';
|
|
70
|
+
readonly remove: 'Remove';
|
|
71
|
+
readonly removeEdge: 'Remove this edge';
|
|
72
|
+
readonly removeNamed: 'Remove {name}';
|
|
73
|
+
readonly removeValue: 'Remove this value';
|
|
74
|
+
readonly resizePanes: 'Resize the panes';
|
|
75
|
+
readonly retry: 'Try again';
|
|
76
|
+
readonly search: 'Search';
|
|
77
|
+
readonly selectOption: 'Please select one of these options.';
|
|
78
|
+
readonly shortcuts: 'Shortcuts';
|
|
79
|
+
readonly showMore: 'Show more';
|
|
80
|
+
readonly showMoreCount: 'Show {count} more';
|
|
81
|
+
readonly shownOfTotal: '{shown} of {total}';
|
|
82
|
+
readonly showOptions: 'Show the options';
|
|
83
|
+
readonly showPassword: 'Show the password';
|
|
84
|
+
readonly stay: 'Keep editing';
|
|
85
|
+
readonly stepCurrent: ', current step';
|
|
86
|
+
readonly stepDone: ', completed';
|
|
87
|
+
readonly tidyLayout: 'Tidy up the layout';
|
|
88
|
+
readonly zoomIn: 'Zoom in';
|
|
89
|
+
readonly zoomOut: 'Zoom out';
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Gives jlib's components their texts in the page's language, before they are drawn: once at start, as a page
|
|
93
|
+
* reads its own messages. A text left out stays English.
|
|
94
|
+
*/
|
|
95
|
+
export declare function setTexts(texts: JlTexts): void;
|
|
96
|
+
/** One of jlib's texts, in the language the page set, its `{placeholders}` filled. */
|
|
97
|
+
export declare const jlText: (key: JlTextKey, values?: Readonly<Record<string, string>>) => string;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { fillText } from "./text.js";
|
|
2
|
+
// src/lib/texts.ts
|
|
3
|
+
/**
|
|
4
|
+
* Every text jlib's components show or say on their own, in English: labels for screen readers, buttons, states,
|
|
5
|
+
* the defaults of their text inputs. `{placeholders}` are filled when the text is shown.
|
|
6
|
+
*/
|
|
7
|
+
var DEFAULT_TEXTS = {
|
|
8
|
+
addTag: "Add at least one tag.",
|
|
9
|
+
addValue: "Add a value",
|
|
10
|
+
back: "Back",
|
|
11
|
+
breadcrumb: "Breadcrumb",
|
|
12
|
+
browse: "Browse",
|
|
13
|
+
chooseDate: "Choose a date",
|
|
14
|
+
chooseDateMissing: "Choose a date.",
|
|
15
|
+
chooseFile: "Choose a file.",
|
|
16
|
+
chooseOption: "Choose an option.",
|
|
17
|
+
chooseRating: "Choose a rating.",
|
|
18
|
+
chosenFiles: "Chosen files",
|
|
19
|
+
clear: "Clear",
|
|
20
|
+
clearSearch: "Clear the search",
|
|
21
|
+
close: "Close",
|
|
22
|
+
closeMenu: "Close the menu",
|
|
23
|
+
collapseMenu: "Collapse the menu",
|
|
24
|
+
commandPalette: "Command palette",
|
|
25
|
+
commandPlaceholder: "Type a command or search…",
|
|
26
|
+
commands: "Commands",
|
|
27
|
+
copied: "Copied",
|
|
28
|
+
copy: "Copy",
|
|
29
|
+
decrease: "Decrease",
|
|
30
|
+
dismiss: "Dismiss",
|
|
31
|
+
downloadCancel: "Cancel",
|
|
32
|
+
downloadFailed: "Not downloaded: {error}",
|
|
33
|
+
downloadPreparing: "Preparing the file… {time}",
|
|
34
|
+
downloadReceived: "{received} received",
|
|
35
|
+
downloadReceivedOf: "{received} of {total}",
|
|
36
|
+
downloadSaved: "Saved as {name}, {size}",
|
|
37
|
+
dragToConnect: "Drag to another node to connect",
|
|
38
|
+
dropFile: "Drop a file here",
|
|
39
|
+
dropFiles: "Drop files here",
|
|
40
|
+
expandMenu: "Expand the menu",
|
|
41
|
+
failedStep: ", failed",
|
|
42
|
+
fileTooLarge: "is larger than {size}",
|
|
43
|
+
fileTooMany: "is one too many: the field takes a single file",
|
|
44
|
+
fileUpTo: "up to {size}",
|
|
45
|
+
fileWrongType: "is not an accepted type ({types})",
|
|
46
|
+
fillField: "Please fill in this field.",
|
|
47
|
+
fitView: "Show every node",
|
|
48
|
+
flow: "Flow",
|
|
49
|
+
hidePassword: "Hide the password",
|
|
50
|
+
increase: "Increase",
|
|
51
|
+
leave: "Leave",
|
|
52
|
+
leaveText: "Your changes are lost.",
|
|
53
|
+
loadError: "This could not be loaded.",
|
|
54
|
+
loading: "Loading",
|
|
55
|
+
loadingMore: "Loading…",
|
|
56
|
+
loadStateError: "Check the connection, then try again. Nothing was changed.",
|
|
57
|
+
mainNavigation: "Main",
|
|
58
|
+
menu: "Menu",
|
|
59
|
+
navigation: "Navigation",
|
|
60
|
+
nextMonth: "Next month",
|
|
61
|
+
nextPage: "Next page",
|
|
62
|
+
noCommands: "No matching commands",
|
|
63
|
+
noData: "No data",
|
|
64
|
+
noResults: "No results",
|
|
65
|
+
notifications: "Notifications",
|
|
66
|
+
pagination: "Pagination",
|
|
67
|
+
previousMonth: "Previous month",
|
|
68
|
+
previousPage: "Previous page",
|
|
69
|
+
progress: "Progress",
|
|
70
|
+
rating: "Rating",
|
|
71
|
+
remove: "Remove",
|
|
72
|
+
removeEdge: "Remove this edge",
|
|
73
|
+
removeNamed: "Remove {name}",
|
|
74
|
+
removeValue: "Remove this value",
|
|
75
|
+
resizePanes: "Resize the panes",
|
|
76
|
+
retry: "Try again",
|
|
77
|
+
search: "Search",
|
|
78
|
+
selectOption: "Please select one of these options.",
|
|
79
|
+
shortcuts: "Shortcuts",
|
|
80
|
+
showMore: "Show more",
|
|
81
|
+
showMoreCount: "Show {count} more",
|
|
82
|
+
shownOfTotal: "{shown} of {total}",
|
|
83
|
+
showOptions: "Show the options",
|
|
84
|
+
showPassword: "Show the password",
|
|
85
|
+
stay: "Keep editing",
|
|
86
|
+
stepCurrent: ", current step",
|
|
87
|
+
stepDone: ", completed",
|
|
88
|
+
tidyLayout: "Tidy up the layout",
|
|
89
|
+
zoomIn: "Zoom in",
|
|
90
|
+
zoomOut: "Zoom out"
|
|
91
|
+
};
|
|
92
|
+
var current = { ...DEFAULT_TEXTS };
|
|
93
|
+
/**
|
|
94
|
+
* Gives jlib's components their texts in the page's language, before they are drawn: once at start, as a page
|
|
95
|
+
* reads its own messages. A text left out stays English.
|
|
96
|
+
*/
|
|
97
|
+
function setTexts(texts) {
|
|
98
|
+
Object.assign(current, texts);
|
|
99
|
+
}
|
|
100
|
+
/** One of jlib's texts, in the language the page set, its `{placeholders}` filled. */
|
|
101
|
+
var jlText = (key, values = {}) => fillText(current[key], values);
|
|
102
|
+
export { DEFAULT_TEXTS, jlText, setTexts };
|
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 };
|
|
@@ -35,7 +35,7 @@ var JlAccountButton = class extends JlElement {
|
|
|
35
35
|
/** Their account page is the one shown: marked as the side nav marks its current place. */
|
|
36
36
|
current = this.useChange(false, (value) => this.renderCurrent(value), { attribute: "current" });
|
|
37
37
|
_refs = this.useRefs((ref) => ({
|
|
38
|
-
avatar: ref(
|
|
38
|
+
avatar: ref(JlAvatar),
|
|
39
39
|
button: ref("button"),
|
|
40
40
|
content: ref(".content"),
|
|
41
41
|
description: ref(".description"),
|
|
@@ -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 { TONES, 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 { hasSlotted } from "../lib/slots.js";
|
|
8
9
|
import { JlButton } from "../atoms/jl-button.js";
|
|
@@ -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,6 +3,7 @@ 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 { jlText } from "../lib/texts.js";
|
|
6
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
7
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";
|
|
@@ -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,6 +3,7 @@ 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 { 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 { rovingIndex } from "../lib/roving-index.js";
|
|
@@ -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"),
|