@syware/jlib 0.5.0 → 0.6.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.
Files changed (64) hide show
  1. package/dist/all.js +5 -3
  2. package/dist/atoms/jl-app-icon.css_raw.js +3 -0
  3. package/dist/atoms/jl-app-icon.d.ts +29 -0
  4. package/dist/atoms/jl-app-icon.js +64 -0
  5. package/dist/atoms/jl-avatar.js +1 -1
  6. package/dist/atoms/jl-badge.js +8 -1
  7. package/dist/atoms/jl-button.js +1 -1
  8. package/dist/atoms/jl-input.js +1 -1
  9. package/dist/atoms/jl-link.js +1 -1
  10. package/dist/atoms/jl-select.js +1 -1
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +4 -2
  13. package/dist/lib/text.d.ts +10 -0
  14. package/dist/lib/text.js +13 -1
  15. package/dist/lib/time.d.ts +5 -3
  16. package/dist/lib/time.js +23 -15
  17. package/dist/lib/trigger.js +1 -1
  18. package/dist/molecules/jl-account-button.css_raw.js +1 -1
  19. package/dist/molecules/jl-account-button.d.ts +8 -1
  20. package/dist/molecules/jl-account-button.js +8 -1
  21. package/dist/molecules/jl-alert.js +1 -1
  22. package/dist/molecules/jl-calendar.js +1 -1
  23. package/dist/molecules/jl-chip-group.js +1 -1
  24. package/dist/molecules/jl-combobox.js +1 -1
  25. package/dist/molecules/jl-date-picker.js +1 -1
  26. package/dist/molecules/jl-empty.js +1 -1
  27. package/dist/molecules/jl-file-drop.js +1 -1
  28. package/dist/molecules/jl-list-item.js +1 -1
  29. package/dist/molecules/jl-load-state.d.ts +4 -1
  30. package/dist/molecules/jl-load-state.js +14 -5
  31. package/dist/molecules/jl-menu.js +1 -1
  32. package/dist/molecules/jl-number-input.js +1 -1
  33. package/dist/molecules/jl-search-button.js +1 -1
  34. package/dist/molecules/jl-search.js +1 -1
  35. package/dist/molecules/jl-segmented.js +1 -1
  36. package/dist/molecules/jl-tabs.js +1 -1
  37. package/dist/molecules/jl-tag-input.js +1 -1
  38. package/dist/molecules/jl-timeline.js +1 -1
  39. package/dist/molecules/jl-tooltip.css_raw.js +1 -1
  40. package/dist/molecules/jl-tooltip.d.ts +29 -1
  41. package/dist/molecules/jl-tooltip.js +144 -5
  42. package/dist/organisms/jl-command-palette.css_raw.js +1 -1
  43. package/dist/organisms/jl-command-palette.js +1 -1
  44. package/dist/organisms/jl-confirm.d.ts +2 -1
  45. package/dist/organisms/jl-confirm.js +16 -8
  46. package/dist/organisms/jl-flow.js +1 -1
  47. package/dist/organisms/jl-side-nav.js +1 -1
  48. package/dist/organisms/jl-tab-bar.js +1 -1
  49. package/dist/organisms/jl-table.js +1 -1
  50. package/dist/organisms/jl-toaster.css_raw.js +1 -1
  51. package/dist/organisms/jl-tree.js +1 -1
  52. package/dist/styles/tokens.css_raw.js +1 -1
  53. package/dist/templates/jl-app-shell.d.ts +6 -1
  54. package/dist/templates/jl-app-shell.js +27 -2
  55. package/dist/templates/jl-auth-layout.css_raw.js +3 -0
  56. package/dist/templates/jl-auth-layout.d.ts +35 -0
  57. package/dist/templates/jl-auth-layout.js +139 -0
  58. package/dist/templates/jl-page.css_raw.js +1 -1
  59. package/dist/templates/jl-split-view.css_raw.js +1 -1
  60. package/dist/templates/jl-split-view.d.ts +21 -1
  61. package/dist/templates/jl-split-view.js +33 -1
  62. package/dist/tokens.css +2 -0
  63. package/dist/types/jl-split-view.types.d.ts +2 -0
  64. package/package.json +1 -1
package/dist/all.js CHANGED
@@ -10,6 +10,7 @@ import { hasIcon, iconElement, iconNames, registerIcons } from "./lib/icons.js";
10
10
  import { CONTROL_SIZES, TONES, TONE_ICONS, TONE_ICON_FILLED } from "./lib/options.js";
11
11
  import { formatDuration, formatRelativeTime } from "./lib/time.js";
12
12
  import { JlIcon } from "./atoms/jl-icon.js";
13
+ import { JlAppIcon } from "./atoms/jl-app-icon.js";
13
14
  import { AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, JlAvatar } from "./atoms/jl-avatar.js";
14
15
  import { JlBadge } from "./atoms/jl-badge.js";
15
16
  import { JlSpinner } from "./atoms/jl-spinner.js";
@@ -75,9 +76,10 @@ import { JlTable, TABLE_SORT_DIRECTIONS } from "./organisms/jl-table.js";
75
76
  import { JlToaster, TOASTER_PLACEMENTS, toast } from "./organisms/jl-toaster.js";
76
77
  import { JlTree } from "./organisms/jl-tree.js";
77
78
  import { JlAppShell } from "./templates/jl-app-shell.js";
79
+ import { JlAuthLayout } from "./templates/jl-auth-layout.js";
78
80
  import { JlPage, PAGE_WIDTHS } from "./templates/jl-page.js";
79
- import { JlSplitView, SPLIT_ORIENTATIONS } from "./templates/jl-split-view.js";
81
+ import { JlSplitView, SPLIT_ORIENTATIONS, SPLIT_PANES } from "./templates/jl-split-view.js";
80
82
  // src/all.ts
81
83
  registerIcons(COMMON_ICONS);
82
- define(JlAccordion, JlAccordionItem, JlAccountButton, JlAlert, JlAppShell, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlChipGroup, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlEmpty, JlField, JlFileDrop, JlFlow, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlLoadState, JlMenu, JlNavbar, JlNumberInput, JlPage, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSearchButton, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabBar, JlTable, JlTabPanel, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree);
83
- export { ACCORDION_VARIANTS, AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, BASE_STYLES, BUTTON_TYPES, BUTTON_VARIANTS, CARD_PADDINGS, CHIP_SIZES, CODE_LANGUAGES, COMMON_ICONS, CONFIRM_TONES, CONTROL_SIZES, CONTROL_STYLES, DIALOG_SIZES, DIVIDER_ALIGNS, DRAWER_PLACEMENTS, DRAWER_SIZES, EMPTY_SIZES, FIELD_ORIENTATIONS, FLOATING_STYLES, INPUT_TYPES, JlAccordion, JlAccordionItem, JlAccountButton, JlAlert, JlAppShell, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlChipGroup, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlElement, JlEmpty, JlField, JlFileDrop, JlFlow, JlFormControl, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlLoadState, JlMenu, JlNavbar, JlNumberInput, JlPage, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSearchButton, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabBar, JlTabPanel, JlTable, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree, LINK_VARIANTS, LOAD_SKELETONS, LOAD_STATES, PAGE_WIDTHS, PLACEMENTS, PROGRESS_SIZES, PROGRESS_TONES, RADIO_GROUP_ORIENTATIONS, RADIO_GROUP_VARIANTS, SKELETON_SHAPES, SPLIT_ORIENTATIONS, STAT_TRENDS, STEPS_ORIENTATIONS, SWITCH_SIZES, TABLE_SORT_DIRECTIONS, TAB_VARIANTS, TOASTER_PLACEMENTS, TOAST_TONES, TOKEN_STYLES, TONES, TONE_ICONS, TONE_ICON_FILLED, adoptTokens, clampedNumber, computePosition, confirmDialog, define, followAnchor, formatDuration, formatRelativeTime, guardLeave, hasIcon, iconElement, iconNames, jsonOf, oneOf, placeFloating, registerIcons, toast };
84
+ define(JlAccordion, JlAccordionItem, JlAccountButton, JlAlert, JlAppIcon, JlAppShell, JlAuthLayout, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlChipGroup, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlEmpty, JlField, JlFileDrop, JlFlow, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlLoadState, JlMenu, JlNavbar, JlNumberInput, JlPage, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSearchButton, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabBar, JlTable, JlTabPanel, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree);
85
+ export { ACCORDION_VARIANTS, AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, BASE_STYLES, BUTTON_TYPES, BUTTON_VARIANTS, CARD_PADDINGS, CHIP_SIZES, CODE_LANGUAGES, COMMON_ICONS, CONFIRM_TONES, CONTROL_SIZES, CONTROL_STYLES, DIALOG_SIZES, DIVIDER_ALIGNS, DRAWER_PLACEMENTS, DRAWER_SIZES, EMPTY_SIZES, FIELD_ORIENTATIONS, FLOATING_STYLES, INPUT_TYPES, JlAccordion, JlAccordionItem, JlAccountButton, JlAlert, JlAppIcon, JlAppShell, JlAuthLayout, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlChipGroup, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlElement, JlEmpty, JlField, JlFileDrop, JlFlow, JlFormControl, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlLoadState, JlMenu, JlNavbar, JlNumberInput, JlPage, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSearchButton, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabBar, JlTabPanel, JlTable, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree, LINK_VARIANTS, LOAD_SKELETONS, LOAD_STATES, PAGE_WIDTHS, PLACEMENTS, PROGRESS_SIZES, PROGRESS_TONES, RADIO_GROUP_ORIENTATIONS, RADIO_GROUP_VARIANTS, SKELETON_SHAPES, SPLIT_ORIENTATIONS, SPLIT_PANES, STAT_TRENDS, STEPS_ORIENTATIONS, SWITCH_SIZES, TABLE_SORT_DIRECTIONS, TAB_VARIANTS, TOASTER_PLACEMENTS, TOAST_TONES, TOKEN_STYLES, TONES, TONE_ICONS, TONE_ICON_FILLED, adoptTokens, clampedNumber, computePosition, confirmDialog, define, followAnchor, formatDuration, formatRelativeTime, guardLeave, hasIcon, iconElement, iconNames, jsonOf, oneOf, placeFloating, registerIcons, toast };
@@ -0,0 +1,3 @@
1
+ // src/atoms/jl-app-icon.css?raw
2
+ var jl_app_icon_default = ":host {\n display: inline-flex;\n flex: none;\n vertical-align: middle;\n}\n\n/* The same in both themes, as the favicon is: the brand's blue, the glyph in white. */\n.tile {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--size, 28px);\n height: var(--size, 28px);\n border-radius: var(--corner, 7px);\n background: var(--jl-brand);\n color: var(--jl-on-brand);\n}\n";
3
+ export { jl_app_icon_default as default };
@@ -0,0 +1,29 @@
1
+ import { JlElement } from '../base/jl-element';
2
+ /**
3
+ * An app's icon: its glyph in white on a rounded tile of the brand's blue, one family for every SyWare app. Beside
4
+ * the wordmark at the top of the side nav, alone in a folded rail or a phone's top bar; the favicon and the home
5
+ * screen icon draw the same tile. The SyWare mark stays the company's. Decorative unless it has a `label`.
6
+ */
7
+ export declare class JlAppIcon extends JlElement {
8
+ static readonly selector = "jl-app-icon";
9
+ /** The app's glyph, a registered icon name: `workflow`, `package`. */
10
+ readonly icon: Readonly<Readonly<{
11
+ get(): string;
12
+ set(setter: string | ((prevState: string) => string)): void;
13
+ }>>;
14
+ /** The tile's side, in pixels. */
15
+ readonly size: Readonly<Readonly<{
16
+ get(): number;
17
+ set(setter: number | ((prevState: number) => number)): void;
18
+ }>>;
19
+ /** The app's name, for screen readers when no wordmark beside it says it. */
20
+ readonly label: Readonly<Readonly<{
21
+ get(): string;
22
+ set(setter: string | ((prevState: string) => string)): void;
23
+ }>>;
24
+ private readonly _refs;
25
+ templateHtml(): Node;
26
+ templateCss(): string;
27
+ private renderSize;
28
+ private renderLabel;
29
+ }
@@ -0,0 +1,64 @@
1
+ import { BASE_STYLES } from "../styles/shared.js";
2
+ import { JlElement } from "../base/jl-element.js";
3
+ import { clampedNumber } from "../lib/attributes.js";
4
+ import jl_app_icon_default from "./jl-app-icon.css_raw.js";
5
+ import { JlIcon } from "./jl-icon.js";
6
+ import { css } from "@jadis/core";
7
+ import { jsx } from "@jadis/core/jsx-runtime";
8
+ // src/atoms/jl-app-icon.tsx
9
+ var DEFAULT_SIZE = 28;
10
+ var MIN_SIZE = 12;
11
+ var MAX_SIZE = 512;
12
+ var GLYPH_SHARE = .62;
13
+ var CORNER_SHARE = .26;
14
+ /**
15
+ * An app's icon: its glyph in white on a rounded tile of the brand's blue, one family for every SyWare app. Beside
16
+ * the wordmark at the top of the side nav, alone in a folded rail or a phone's top bar; the favicon and the home
17
+ * screen icon draw the same tile. The SyWare mark stays the company's. Decorative unless it has a `label`.
18
+ */
19
+ var JlAppIcon = class extends JlElement {
20
+ static selector = "jl-app-icon";
21
+ /** The app's glyph, a registered icon name: `workflow`, `package`. */
22
+ icon = this.useChange("", (value) => this._refs.glyph.name.set(value), { attribute: "icon" });
23
+ /** The tile's side, in pixels. */
24
+ size = this.useChange(DEFAULT_SIZE, (value) => this.renderSize(value), {
25
+ attribute: "size",
26
+ parse: clampedNumber(DEFAULT_SIZE, MIN_SIZE, MAX_SIZE)
27
+ });
28
+ /** The app's name, for screen readers when no wordmark beside it says it. */
29
+ label = this.useChange("", (value) => this.renderLabel(value), { attribute: "label" });
30
+ _refs = this.useRefs((ref) => ({
31
+ glyph: ref("jl-icon"),
32
+ tile: ref(".tile")
33
+ }));
34
+ templateHtml() {
35
+ return /* @__PURE__ */ jsx("span", {
36
+ class: "tile",
37
+ "aria-hidden": "true",
38
+ attrs: { part: "base" },
39
+ children: /* @__PURE__ */ jsx(JlIcon, { size: Math.round(DEFAULT_SIZE * GLYPH_SHARE) })
40
+ });
41
+ }
42
+ templateCss() {
43
+ return css`${BASE_STYLES}${jl_app_icon_default}`;
44
+ }
45
+ renderSize(size) {
46
+ this._refs.tile.style.setProperty("--size", `${size}px`);
47
+ this._refs.tile.style.setProperty("--corner", `${Math.round(size * CORNER_SHARE)}px`);
48
+ this._refs.glyph.size.set(Math.round(size * GLYPH_SHARE));
49
+ }
50
+ renderLabel(label) {
51
+ const tile = this._refs.tile;
52
+ if (label === "") {
53
+ tile.setAttribute("aria-hidden", "true");
54
+ tile.removeAttribute("role");
55
+ tile.removeAttribute("aria-label");
56
+ return;
57
+ }
58
+ tile.removeAttribute("aria-hidden");
59
+ tile.setAttribute("role", "img");
60
+ tile.setAttribute("aria-label", label);
61
+ }
62
+ };
63
+ JlAppIcon.register();
64
+ export { JlAppIcon };
@@ -2,11 +2,11 @@ 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 { JlIcon } from "./jl-icon.js";
5
6
  import { initialsOf, pickStable } from "../lib/avatar.js";
6
7
  import { setOrRemove } from "../lib/dom.js";
7
8
  import { hasSlotted } from "../lib/slots.js";
8
9
  import jl_avatar_default from "./jl-avatar.css_raw.js";
9
- import { JlIcon } from "./jl-icon.js";
10
10
  import { css } from "@jadis/core";
11
11
  import { User } from "lucide";
12
12
  import { jsx, jsxs } from "@jadis/core/jsx-runtime";
@@ -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 { TONES } from "../lib/options.js";
5
- import { setOrRemove } from "../lib/dom.js";
6
5
  import { JlIcon } from "./jl-icon.js";
6
+ import { setOrRemove } from "../lib/dom.js";
7
7
  import jl_badge_default from "./jl-badge.css_raw.js";
8
8
  import { css } from "@jadis/core";
9
9
  import { jsx, jsxs } from "@jadis/core/jsx-runtime";
@@ -36,6 +36,13 @@ var JlBadge = class extends JlElement {
36
36
  }));
37
37
  /** Shows a state as an app's map of states describes it: its label, tone, icon and hint. */
38
38
  showStatus(look) {
39
+ const attributes = {
40
+ hint: look.hint ?? "",
41
+ icon: look.icon ?? "",
42
+ label: look.label,
43
+ tone: look.tone
44
+ };
45
+ for (const [name, value] of Object.entries(attributes)) setOrRemove(this, name, value);
39
46
  this.label.set(look.label);
40
47
  this.tone.set(look.tone);
41
48
  this.icon.set(look.icon ?? "");
@@ -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 { CONTROL_SIZES } from "../lib/options.js";
5
- import { setOrRemove } from "../lib/dom.js";
6
5
  import { JlIcon } from "./jl-icon.js";
6
+ import { setOrRemove } from "../lib/dom.js";
7
7
  import jl_button_default from "./jl-button.css_raw.js";
8
8
  import { JlSpinner } from "./jl-spinner.js";
9
9
  import { css } from "@jadis/core";
@@ -3,8 +3,8 @@ 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 { setOrRemove } from "../lib/dom.js";
7
6
  import { JlIcon } from "./jl-icon.js";
7
+ import { setOrRemove } from "../lib/dom.js";
8
8
  import jl_input_default from "./jl-input.css_raw.js";
9
9
  import { css } from "@jadis/core";
10
10
  import { Eye, EyeOff, X } from "lucide";
@@ -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 { setOrRemove } from "../lib/dom.js";
6
5
  import { JlIcon } from "./jl-icon.js";
6
+ import { setOrRemove } from "../lib/dom.js";
7
7
  import jl_link_default from "./jl-link.css_raw.js";
8
8
  import { css } from "@jadis/core";
9
9
  import { ExternalLink } from "lucide";
@@ -3,8 +3,8 @@ import { JlFormControl } from "../base/jl-form-control.js";
3
3
  import { jsonOf, oneOf } from "../lib/attributes.js";
4
4
  import { registerIcons } from "../lib/icons.js";
5
5
  import { CONTROL_SIZES } from "../lib/options.js";
6
- import { setOrRemove } from "../lib/dom.js";
7
6
  import { JlIcon } from "./jl-icon.js";
7
+ import { setOrRemove } from "../lib/dom.js";
8
8
  import { groupOptions } from "../lib/option-groups.js";
9
9
  import jl_select_default from "./jl-select.css_raw.js";
10
10
  import { css } from "@jadis/core";
package/dist/index.d.ts CHANGED
@@ -63,6 +63,7 @@ export type * from './types/options.types';
63
63
  export type * from './types/pagination.types';
64
64
  export type * from './types/roving-index.types';
65
65
  export type * from './types/sparkline.types';
66
+ export * from './atoms/jl-app-icon';
66
67
  export * from './atoms/jl-avatar';
67
68
  export * from './atoms/jl-badge';
68
69
  export * from './atoms/jl-button';
@@ -129,5 +130,6 @@ export * from './organisms/jl-table';
129
130
  export * from './organisms/jl-toaster';
130
131
  export * from './organisms/jl-tree';
131
132
  export * from './templates/jl-app-shell';
133
+ export * from './templates/jl-auth-layout';
132
134
  export * from './templates/jl-page';
133
135
  export * from './templates/jl-split-view';
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { hasIcon, iconElement, iconNames, registerIcons } from "./lib/icons.js";
10
10
  import { CONTROL_SIZES, TONES, TONE_ICONS, TONE_ICON_FILLED } from "./lib/options.js";
11
11
  import { formatDuration, formatRelativeTime } from "./lib/time.js";
12
12
  import { JlIcon } from "./atoms/jl-icon.js";
13
+ import { JlAppIcon } from "./atoms/jl-app-icon.js";
13
14
  import { AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, JlAvatar } from "./atoms/jl-avatar.js";
14
15
  import { JlBadge } from "./atoms/jl-badge.js";
15
16
  import { JlSpinner } from "./atoms/jl-spinner.js";
@@ -75,6 +76,7 @@ import { JlTable, TABLE_SORT_DIRECTIONS } from "./organisms/jl-table.js";
75
76
  import { JlToaster, TOASTER_PLACEMENTS, toast } from "./organisms/jl-toaster.js";
76
77
  import { JlTree } from "./organisms/jl-tree.js";
77
78
  import { JlAppShell } from "./templates/jl-app-shell.js";
79
+ import { JlAuthLayout } from "./templates/jl-auth-layout.js";
78
80
  import { JlPage, PAGE_WIDTHS } from "./templates/jl-page.js";
79
- import { JlSplitView, SPLIT_ORIENTATIONS } from "./templates/jl-split-view.js";
80
- export { ACCORDION_VARIANTS, AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, BASE_STYLES, BUTTON_TYPES, BUTTON_VARIANTS, CARD_PADDINGS, CHIP_SIZES, CODE_LANGUAGES, COMMON_ICONS, CONFIRM_TONES, CONTROL_SIZES, CONTROL_STYLES, DIALOG_SIZES, DIVIDER_ALIGNS, DRAWER_PLACEMENTS, DRAWER_SIZES, EMPTY_SIZES, FIELD_ORIENTATIONS, FLOATING_STYLES, INPUT_TYPES, JlAccordion, JlAccordionItem, JlAccountButton, JlAlert, JlAppShell, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlChipGroup, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlElement, JlEmpty, JlField, JlFileDrop, JlFlow, JlFormControl, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlLoadState, JlMenu, JlNavbar, JlNumberInput, JlPage, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSearchButton, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabBar, JlTabPanel, JlTable, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree, LINK_VARIANTS, LOAD_SKELETONS, LOAD_STATES, PAGE_WIDTHS, PLACEMENTS, PROGRESS_SIZES, PROGRESS_TONES, RADIO_GROUP_ORIENTATIONS, RADIO_GROUP_VARIANTS, SKELETON_SHAPES, SPLIT_ORIENTATIONS, STAT_TRENDS, STEPS_ORIENTATIONS, SWITCH_SIZES, TABLE_SORT_DIRECTIONS, TAB_VARIANTS, TOASTER_PLACEMENTS, TOAST_TONES, TOKEN_STYLES, TONES, TONE_ICONS, TONE_ICON_FILLED, adoptTokens, clampedNumber, computePosition, confirmDialog, define, followAnchor, formatDuration, formatRelativeTime, guardLeave, hasIcon, iconElement, iconNames, jsonOf, oneOf, placeFloating, registerIcons, toast };
81
+ import { JlSplitView, SPLIT_ORIENTATIONS, SPLIT_PANES } from "./templates/jl-split-view.js";
82
+ export { ACCORDION_VARIANTS, AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, BASE_STYLES, BUTTON_TYPES, BUTTON_VARIANTS, CARD_PADDINGS, CHIP_SIZES, CODE_LANGUAGES, COMMON_ICONS, CONFIRM_TONES, CONTROL_SIZES, CONTROL_STYLES, DIALOG_SIZES, DIVIDER_ALIGNS, DRAWER_PLACEMENTS, DRAWER_SIZES, EMPTY_SIZES, FIELD_ORIENTATIONS, FLOATING_STYLES, INPUT_TYPES, JlAccordion, JlAccordionItem, JlAccountButton, JlAlert, JlAppIcon, JlAppShell, JlAuthLayout, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlChipGroup, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlElement, JlEmpty, JlField, JlFileDrop, JlFlow, JlFormControl, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlLoadState, JlMenu, JlNavbar, JlNumberInput, JlPage, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSearchButton, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabBar, JlTabPanel, JlTable, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree, LINK_VARIANTS, LOAD_SKELETONS, LOAD_STATES, PAGE_WIDTHS, PLACEMENTS, PROGRESS_SIZES, PROGRESS_TONES, RADIO_GROUP_ORIENTATIONS, RADIO_GROUP_VARIANTS, SKELETON_SHAPES, SPLIT_ORIENTATIONS, SPLIT_PANES, STAT_TRENDS, STEPS_ORIENTATIONS, SWITCH_SIZES, TABLE_SORT_DIRECTIONS, TAB_VARIANTS, TOASTER_PLACEMENTS, TOAST_TONES, TOKEN_STYLES, TONES, TONE_ICONS, TONE_ICON_FILLED, adoptTokens, clampedNumber, computePosition, confirmDialog, define, followAnchor, formatDuration, formatRelativeTime, guardLeave, hasIcon, iconElement, iconNames, jsonOf, oneOf, placeFloating, registerIcons, toast };
@@ -3,3 +3,13 @@
3
3
  * an HTML element reads as it was meant.
4
4
  */
5
5
  export declare function dedent(text: string): string;
6
+ /** A run of a headline: plain, or `accent` for the words written between asterisks. */
7
+ export type StarredPart = {
8
+ text: string;
9
+ accent: boolean;
10
+ };
11
+ /**
12
+ * A headline's runs: the words between asterisks are the accented ones, "Workflows that *ask* before they act."
13
+ * A lone asterisk stays as it is; empty runs are left out.
14
+ */
15
+ export declare function starredParts(text: string): StarredPart[];
package/dist/lib/text.js CHANGED
@@ -10,4 +10,16 @@ function dedent(text) {
10
10
  const shared = indents.length === 0 ? 0 : Math.min(...indents);
11
11
  return lines.map((line) => line.slice(shared)).join("\n");
12
12
  }
13
- export { dedent };
13
+ var STAR = "*";
14
+ /**
15
+ * A headline's runs: the words between asterisks are the accented ones, "Workflows that *ask* before they act."
16
+ * A lone asterisk stays as it is; empty runs are left out.
17
+ */
18
+ function starredParts(text) {
19
+ const pieces = text.split(STAR);
20
+ return (pieces.length % 2 === 1 ? pieces : [...pieces.slice(0, -2), `${pieces.at(-2)}${STAR}${pieces.at(-1)}`]).map((piece, index) => ({
21
+ accent: index % 2 === 1,
22
+ text: piece
23
+ })).filter((part) => part.text !== "");
24
+ }
25
+ export { dedent, starredParts };
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * A duration in the units that read best: "< 1 sec" under a second (never "0.0 s"), then seconds, minutes, hours
3
- * and minutes, days and hours.
3
+ * and minutes, days and hours. The unit is chosen once rounded: 59.6 seconds is "1 min", not "60 secs". Not a
4
+ * number gives "".
4
5
  */
5
6
  export declare function formatDuration(milliseconds: number, locale?: string): string;
6
7
  /**
7
- * When something happened, from `now`: "now", "5 minutes ago", "3 hours ago", "yesterday" within a week, then the
8
- * date ("12 Mar", with the year when it is not this year's). Times to come read the same way: "in 5 minutes".
8
+ * When something happened, from `now`: "now", "5 minutes ago", "3 hours ago" the same day, "yesterday" or "3 days
9
+ * ago" by the calendar within a week, then the date ("12 Mar", with the year when it is not this year's). Times to
10
+ * come read the same way: "in 5 minutes". A date that is not one gives "".
9
11
  */
10
12
  export declare function formatRelativeTime(date: Date | number | string, now: Date | number, locale?: string): string;
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 HOURS_UNDER_S = 22 * HOUR_S;
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
- if (seconds < MINUTE_S) return unitText(Math.round(seconds), "second", locale);
36
- if (seconds < HOUR_S) return unitText(Math.round(seconds / MINUTE_S), "minute", locale);
37
- if (seconds < DAY_S) {
38
- const minutes = Math.round(seconds / MINUTE_S);
39
- return pair([Math.floor(minutes / MINUTES_PER_HOUR), "hour"], [minutes % MINUTES_PER_HOUR, "minute"], locale);
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" within a week, then the
46
- * date ("12 Mar", with the year when it is not this year's). Times to come read the same way: "in 5 minutes".
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 seconds = (then.getTime() - new Date(now).getTime()) / SECOND_MS;
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
- if (distance < HOURS_UNDER_S) return relative.format(Math.round(seconds / HOUR_S), "hour");
56
- if (distance < DAYS_UNDER_S) return relative.format(Math.round(seconds / DAY_S), "day");
57
- const sameYear = then.getFullYear() === new Date(now).getFullYear();
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",
@@ -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,6 +32,8 @@ 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
38
  avatar: ref("jl-avatar"),
36
39
  button: ref("button"),
@@ -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,8 @@ 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 { hasSlotted } from "../lib/slots.js";
7
6
  import { JlIcon } from "../atoms/jl-icon.js";
7
+ import { hasSlotted } from "../lib/slots.js";
8
8
  import { JlButton } from "../atoms/jl-button.js";
9
9
  import jl_alert_default from "./jl-alert.css_raw.js";
10
10
  import { css } from "@jadis/core";
@@ -3,8 +3,8 @@ 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 { setOrRemove, uniqueId } from "../lib/dom.js";
7
6
  import { JlIcon } from "../atoms/jl-icon.js";
7
+ import { setOrRemove, uniqueId } from "../lib/dom.js";
8
8
  import { addMonths, calendarDateOf, clampDate, dateAfterKey, dateFormatter, formatMonthTitle, isSameDate, isSameMonth, isWithin, monthGrid, monthHasDaysWithin, parseIsoDate, toIsoDate, weekdayNames } from "../lib/calendar.js";
9
9
  import { pageLocale } from "../lib/locale.js";
10
10
  import jl_calendar_default from "./jl-calendar.css_raw.js";
@@ -3,8 +3,8 @@ 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 { setOrRemove } from "../lib/dom.js";
7
6
  import { JlIcon } from "../atoms/jl-icon.js";
7
+ import { setOrRemove } from "../lib/dom.js";
8
8
  import { rovingIndex } from "../lib/roving-index.js";
9
9
  import jl_chip_group_default from "./jl-chip-group.css_raw.js";
10
10
  import { css } from "@jadis/core";
@@ -4,8 +4,8 @@ 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 { setOrRemove, uniqueId } from "../lib/dom.js";
8
7
  import { JlIcon } from "../atoms/jl-icon.js";
8
+ import { setOrRemove, uniqueId } from "../lib/dom.js";
9
9
  import { keepInView } from "../lib/keep-in-view.js";
10
10
  import { edgeEnabledIndex, filterOptions, foldText, matchParts, nextEnabledIndex } from "../lib/option-filter.js";
11
11
  import jl_combobox_default from "./jl-combobox.css_raw.js";
@@ -4,8 +4,8 @@ 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 { setOrRemove, uniqueId } from "../lib/dom.js";
8
7
  import { JlIcon } from "../atoms/jl-icon.js";
8
+ import { setOrRemove, uniqueId } from "../lib/dom.js";
9
9
  import { NUMERIC_DATE, compareDates, dateOrder, datePattern, formatDate, isDateText, parseIsoDate, parseTypedDate, toIsoDate } from "../lib/calendar.js";
10
10
  import { pageLocale } from "../lib/locale.js";
11
11
  import { JlCalendar } from "./jl-calendar.js";
@@ -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";
@@ -3,8 +3,8 @@ 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 { setOrRemove, uniqueId } from "../lib/dom.js";
7
6
  import { JlIcon } from "../atoms/jl-icon.js";
7
+ import { setOrRemove, uniqueId } from "../lib/dom.js";
8
8
  import { pageLocale } from "../lib/locale.js";
9
9
  import { checkFiles, describeAccept, formatFileSize, isSameFile } from "../lib/files.js";
10
10
  import jl_file_drop_default from "./jl-file-drop.css_raw.js";
@@ -1,9 +1,9 @@
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 { JlIcon } from "../atoms/jl-icon.js";
4
5
  import { setOrRemove } from "../lib/dom.js";
5
6
  import { hasSlotted } from "../lib/slots.js";
6
- import { JlIcon } from "../atoms/jl-icon.js";
7
7
  import { isActivationKey, startedOnControl } from "../lib/surface.js";
8
8
  import jl_list_item_default from "./jl-list-item.css_raw.js";
9
9
  import { css } from "@jadis/core";
@@ -49,9 +49,12 @@ export declare class JlLoadState extends JlElement {
49
49
  /**
50
50
  * Fetches the data and draws it. The first time, and after a failure, the skeleton shows while it comes; later
51
51
  * (a refresh), what is shown stays until the new data is there, and stays too if it fails. Resolves to whether it
52
- * worked: a refresh that fails says so only here, for the page to tell people.
52
+ * worked: a refresh that fails says so only here, for the page to tell people. A load overtaken by a later one
53
+ * (a search typed on, a poll during a reload) draws nothing and resolves true: the later one decides.
53
54
  */
54
55
  load<Value>(task: LoadTask<Value>): Promise<boolean>;
56
+ /** Whether data is shown (the content or the empty state), which a refresh keeps. */
57
+ private isShowing;
55
58
  templateHtml(): Node;
56
59
  templateCss(): string;
57
60
  onConnect(): void;
@@ -97,7 +97,7 @@ var JlLoadState = class extends JlElement {
97
97
  errorHeading = this.useChange(DEFAULT_ERROR_HEADING, (value) => this._refs.error.heading.set(value), { attribute: "error-heading" });
98
98
  errorText = this.useChange(DEFAULT_ERROR_TEXT, (value) => this._refs.error.description.set(value), { attribute: "error-text" });
99
99
  retryLabel = this.useChange(DEFAULT_RETRY_LABEL, (value) => this._refs.retry.label.set(value), { attribute: "retry-label" });
100
- _work = {};
100
+ _work = { latest: 0 };
101
101
  _refs = this.useRefs((ref) => ({
102
102
  bones: ref(".bones"),
103
103
  content: ref(".content"),
@@ -109,22 +109,31 @@ var JlLoadState = class extends JlElement {
109
109
  /**
110
110
  * Fetches the data and draws it. The first time, and after a failure, the skeleton shows while it comes; later
111
111
  * (a refresh), what is shown stays until the new data is there, and stays too if it fails. Resolves to whether it
112
- * worked: a refresh that fails says so only here, for the page to tell people.
112
+ * worked: a refresh that fails says so only here, for the page to tell people. A load overtaken by a later one
113
+ * (a search typed on, a poll during a reload) draws nothing and resolves true: the later one decides.
113
114
  */
114
115
  async load(task) {
116
+ this._work.latest += 1;
117
+ const ticket = this._work.latest;
115
118
  this._work.retry = () => this.load(task);
116
- const showing = this.state.get() === "ready" || this.state.get() === "empty";
117
- if (!showing) this.state.set("loading");
119
+ if (!this.isShowing()) this.state.set("loading");
118
120
  try {
119
121
  const value = await task.fetch();
122
+ if (ticket !== this._work.latest) return true;
120
123
  task.draw(value);
121
124
  this.state.set(task.isEmpty?.(value) === true ? "empty" : "ready");
122
125
  return true;
123
126
  } catch {
124
- if (!showing) this.state.set("error");
127
+ if (ticket !== this._work.latest) return true;
128
+ if (!this.isShowing()) this.state.set("error");
125
129
  return false;
126
130
  }
127
131
  }
132
+ /** Whether data is shown (the content or the empty state), which a refresh keeps. */
133
+ isShowing() {
134
+ const state = this.state.get();
135
+ return state === "ready" || state === "empty";
136
+ }
128
137
  templateHtml() {
129
138
  return /* @__PURE__ */ jsxs("div", {
130
139
  class: "load-state",
@@ -2,8 +2,8 @@ import { BASE_STYLES, FLOATING_STYLES } from "../styles/shared.js";
2
2
  import { JlElement } from "../base/jl-element.js";
3
3
  import { jsonOf, oneOf } from "../lib/attributes.js";
4
4
  import { PLACEMENTS, followAnchor } from "../lib/floating.js";
5
- import { uniqueId } from "../lib/dom.js";
6
5
  import { JlIcon } from "../atoms/jl-icon.js";
6
+ import { uniqueId } from "../lib/dom.js";
7
7
  import { firstIndex, lastIndex, letterIndex, stepIndex } from "../lib/roving.js";
8
8
  import { setTriggerAria } from "../lib/trigger.js";
9
9
  import jl_menu_default from "./jl-menu.css_raw.js";