@syware/jlib 0.3.0 → 0.5.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 (56) hide show
  1. package/dist/all.js +10 -3
  2. package/dist/atoms/jl-badge.d.ts +12 -1
  3. package/dist/atoms/jl-badge.js +15 -1
  4. package/dist/atoms/jl-button.css_raw.js +1 -1
  5. package/dist/atoms/jl-button.d.ts +19 -0
  6. package/dist/atoms/jl-button.js +75 -23
  7. package/dist/atoms/jl-chip.css_raw.js +1 -1
  8. package/dist/atoms/jl-input.d.ts +5 -0
  9. package/dist/atoms/jl-input.js +2 -0
  10. package/dist/index.d.ts +12 -0
  11. package/dist/index.js +9 -2
  12. package/dist/lib/attributes.d.ts +5 -0
  13. package/dist/lib/attributes.js +13 -1
  14. package/dist/lib/time.d.ts +10 -0
  15. package/dist/lib/time.js +64 -0
  16. package/dist/lib/tokens.d.ts +2 -1
  17. package/dist/lib/tokens.js +13 -4
  18. package/dist/molecules/jl-account-button.css_raw.js +3 -0
  19. package/dist/molecules/jl-account-button.d.ts +46 -0
  20. package/dist/molecules/jl-account-button.js +97 -0
  21. package/dist/molecules/jl-alert.d.ts +10 -3
  22. package/dist/molecules/jl-alert.js +23 -6
  23. package/dist/molecules/jl-chip-group.css_raw.js +3 -0
  24. package/dist/molecules/jl-chip-group.d.ts +81 -0
  25. package/dist/molecules/jl-chip-group.js +259 -0
  26. package/dist/molecules/jl-load-state.css_raw.js +3 -0
  27. package/dist/molecules/jl-load-state.d.ts +61 -0
  28. package/dist/molecules/jl-load-state.js +200 -0
  29. package/dist/molecules/jl-search-button.css_raw.js +3 -0
  30. package/dist/molecules/jl-search-button.d.ts +34 -0
  31. package/dist/molecules/jl-search-button.js +80 -0
  32. package/dist/molecules/jl-tag-input.css_raw.js +1 -1
  33. package/dist/organisms/jl-confirm.d.ts +7 -1
  34. package/dist/organisms/jl-confirm.js +22 -1
  35. package/dist/organisms/jl-tab-bar.css_raw.js +3 -0
  36. package/dist/organisms/jl-tab-bar.d.ts +43 -0
  37. package/dist/organisms/jl-tab-bar.js +123 -0
  38. package/dist/organisms/jl-toaster.d.ts +4 -1
  39. package/dist/organisms/jl-toaster.js +9 -2
  40. package/dist/styles/control.css_raw.js +1 -1
  41. package/dist/styles/tokens.css_raw.js +1 -1
  42. package/dist/templates/jl-app-shell.css_raw.js +1 -1
  43. package/dist/templates/jl-app-shell.d.ts +8 -2
  44. package/dist/templates/jl-app-shell.js +32 -5
  45. package/dist/templates/jl-page.css_raw.js +3 -0
  46. package/dist/templates/jl-page.d.ts +49 -0
  47. package/dist/templates/jl-page.js +102 -0
  48. package/dist/tokens.css +22 -0
  49. package/dist/types/jl-badge.types.d.ts +11 -0
  50. package/dist/types/jl-chip-group.types.d.ts +10 -0
  51. package/dist/types/jl-confirm.types.d.ts +15 -0
  52. package/dist/types/jl-load-state.types.d.ts +10 -0
  53. package/dist/types/jl-page.types.d.ts +2 -0
  54. package/dist/types/jl-tab-bar.types.d.ts +11 -0
  55. package/dist/types/jl-toaster.types.d.ts +1 -1
  56. package/package.json +1 -1
package/dist/all.js CHANGED
@@ -8,6 +8,7 @@ import { PLACEMENTS, computePosition, followAnchor, placeFloating } from "./lib/
8
8
  import { COMMON_ICONS } from "./lib/icon-set.js";
9
9
  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
+ import { formatDuration, formatRelativeTime } from "./lib/time.js";
11
12
  import { JlIcon } from "./atoms/jl-icon.js";
12
13
  import { AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, JlAvatar } from "./atoms/jl-avatar.js";
13
14
  import { JlBadge } from "./atoms/jl-badge.js";
@@ -29,11 +30,13 @@ import { JlSwitch, SWITCH_SIZES } from "./atoms/jl-switch.js";
29
30
  import { JlTextarea } from "./atoms/jl-textarea.js";
30
31
  import { JlAccordionItem } from "./molecules/jl-accordion-item.js";
31
32
  import { ACCORDION_VARIANTS, JlAccordion } from "./molecules/jl-accordion.js";
33
+ import { JlAccountButton } from "./molecules/jl-account-button.js";
32
34
  import { JlAlert } from "./molecules/jl-alert.js";
33
35
  import { JlAvatarGroup } from "./molecules/jl-avatar-group.js";
34
36
  import { JlBreadcrumb } from "./molecules/jl-breadcrumb.js";
35
37
  import { JlCalendar } from "./molecules/jl-calendar.js";
36
38
  import { CARD_PADDINGS, JlCard } from "./molecules/jl-card.js";
39
+ import { JlChipGroup } from "./molecules/jl-chip-group.js";
37
40
  import { JlCopyButton } from "./molecules/jl-copy-button.js";
38
41
  import { CODE_LANGUAGES, JlCodeBlock } from "./molecules/jl-code-block.js";
39
42
  import { JlCombobox } from "./molecules/jl-combobox.js";
@@ -42,11 +45,13 @@ import { EMPTY_SIZES, JlEmpty } from "./molecules/jl-empty.js";
42
45
  import { FIELD_ORIENTATIONS, JlField } from "./molecules/jl-field.js";
43
46
  import { JlFileDrop } from "./molecules/jl-file-drop.js";
44
47
  import { JlListItem } from "./molecules/jl-list-item.js";
48
+ import { JlLoadState, LOAD_SKELETONS, LOAD_STATES } from "./molecules/jl-load-state.js";
45
49
  import { JlMenu } from "./molecules/jl-menu.js";
46
50
  import { JlNumberInput } from "./molecules/jl-number-input.js";
47
51
  import { JlPagination } from "./molecules/jl-pagination.js";
48
52
  import { JlPopover } from "./molecules/jl-popover.js";
49
53
  import { JlRadioGroup, RADIO_GROUP_ORIENTATIONS, RADIO_GROUP_VARIANTS } from "./molecules/jl-radio-group.js";
54
+ import { JlSearchButton } from "./molecules/jl-search-button.js";
50
55
  import { JlSearch } from "./molecules/jl-search.js";
51
56
  import { JlSegmented } from "./molecules/jl-segmented.js";
52
57
  import { JlStat, STAT_TRENDS } from "./molecules/jl-stat.js";
@@ -59,18 +64,20 @@ import { JlToast, TOAST_TONES } from "./molecules/jl-toast.js";
59
64
  import { JlTooltip } from "./molecules/jl-tooltip.js";
60
65
  import { JlCommandPalette } from "./organisms/jl-command-palette.js";
61
66
  import { DIALOG_SIZES, JlDialog } from "./organisms/jl-dialog.js";
62
- import { CONFIRM_TONES, JlConfirm, confirmDialog } from "./organisms/jl-confirm.js";
67
+ import { CONFIRM_TONES, JlConfirm, confirmDialog, guardLeave } from "./organisms/jl-confirm.js";
63
68
  import { DRAWER_PLACEMENTS, DRAWER_SIZES, JlDrawer } from "./organisms/jl-drawer.js";
64
69
  import { JlFlow } from "./organisms/jl-flow.js";
65
70
  import { JlNavbar } from "./organisms/jl-navbar.js";
66
71
  import { JlPageHeader } from "./organisms/jl-page-header.js";
67
72
  import { JlSideNav } from "./organisms/jl-side-nav.js";
73
+ import { JlTabBar } from "./organisms/jl-tab-bar.js";
68
74
  import { JlTable, TABLE_SORT_DIRECTIONS } from "./organisms/jl-table.js";
69
75
  import { JlToaster, TOASTER_PLACEMENTS, toast } from "./organisms/jl-toaster.js";
70
76
  import { JlTree } from "./organisms/jl-tree.js";
71
77
  import { JlAppShell } from "./templates/jl-app-shell.js";
78
+ import { JlPage, PAGE_WIDTHS } from "./templates/jl-page.js";
72
79
  import { JlSplitView, SPLIT_ORIENTATIONS } from "./templates/jl-split-view.js";
73
80
  // src/all.ts
74
81
  registerIcons(COMMON_ICONS);
75
- define(JlAccordion, JlAccordionItem, JlAlert, JlAppShell, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlEmpty, JlField, JlFileDrop, JlFlow, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlMenu, JlNavbar, JlNumberInput, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTable, JlTabPanel, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree);
76
- 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, JlAlert, JlAppShell, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlElement, JlEmpty, JlField, JlFileDrop, JlFlow, JlFormControl, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlMenu, JlNavbar, JlNumberInput, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabPanel, JlTable, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree, LINK_VARIANTS, 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, hasIcon, iconElement, iconNames, jsonOf, oneOf, placeFloating, registerIcons, toast };
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 };
@@ -1,6 +1,10 @@
1
1
  import { JlElement } from '../base/jl-element';
2
+ import type { StatusLook } from '../types/jl-badge.types';
2
3
  import type { Tone } from '../types/options.types';
3
- /** A short status, coloured by its tone: "Active", "3 new", "Failed". A `dot` marks a live state. */
4
+ /**
5
+ * A short status, coloured by its tone: "Active", "3 new", "Failed". A `dot` marks a live state; a `hint` says what
6
+ * the state means, as a tooltip. `showStatus()` takes the look of a state from an app's map of them.
7
+ */
4
8
  export declare class JlBadge extends JlElement {
5
9
  static readonly selector = "jl-badge";
6
10
  readonly label: Readonly<Readonly<{
@@ -24,7 +28,14 @@ export declare class JlBadge extends JlElement {
24
28
  get(): boolean;
25
29
  set(setter: boolean | ((prevState: boolean) => boolean)): void;
26
30
  }>>;
31
+ /** What the state means, as a tooltip: "Waiting for logistics to prepare it." */
32
+ readonly hint: Readonly<Readonly<{
33
+ get(): string;
34
+ set(setter: string | ((prevState: string) => string)): void;
35
+ }>>;
27
36
  private readonly _refs;
37
+ /** Shows a state as an app's map of states describes it: its label, tone, icon and hint. */
38
+ showStatus(look: StatusLook): void;
28
39
  templateHtml(): Node;
29
40
  templateCss(): string;
30
41
  /** An icon wins over the dot: a badge shows one marker at most. */
@@ -2,13 +2,17 @@ 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";
5
6
  import { JlIcon } from "./jl-icon.js";
6
7
  import jl_badge_default from "./jl-badge.css_raw.js";
7
8
  import { css } from "@jadis/core";
8
9
  import { jsx, jsxs } from "@jadis/core/jsx-runtime";
9
10
  // src/atoms/jl-badge.tsx
10
11
  var ICON_SIZE = 13;
11
- /** A short status, coloured by its tone: "Active", "3 new", "Failed". A `dot` marks a live state. */
12
+ /**
13
+ * A short status, coloured by its tone: "Active", "3 new", "Failed". A `dot` marks a live state; a `hint` says what
14
+ * the state means, as a tooltip. `showStatus()` takes the look of a state from an app's map of them.
15
+ */
12
16
  var JlBadge = class extends JlElement {
13
17
  static selector = "jl-badge";
14
18
  label = this.useChange("", (value) => {
@@ -22,11 +26,21 @@ var JlBadge = class extends JlElement {
22
26
  dot = this.useChange(false, () => this.renderMarker(), { attribute: "dot" });
23
27
  /** Filled with the tone's colour, for what must stand out. */
24
28
  solid = this.useChange(false, (value) => this.reflect("solid", value), { attribute: "solid" });
29
+ /** What the state means, as a tooltip: "Waiting for logistics to prepare it." */
30
+ hint = this.useChange("", (value) => setOrRemove(this._refs.badge, "title", value), { attribute: "hint" });
25
31
  _refs = this.useRefs((ref) => ({
32
+ badge: ref(".badge"),
26
33
  dot: ref(".dot"),
27
34
  icon: ref("jl-icon"),
28
35
  label: ref(".label")
29
36
  }));
37
+ /** Shows a state as an app's map of states describes it: its label, tone, icon and hint. */
38
+ showStatus(look) {
39
+ this.label.set(look.label);
40
+ this.tone.set(look.tone);
41
+ this.icon.set(look.icon ?? "");
42
+ this.hint.set(look.hint ?? "");
43
+ }
30
44
  templateHtml() {
31
45
  return /* @__PURE__ */ jsxs("span", {
32
46
  class: "badge",
@@ -1,3 +1,3 @@
1
1
  // src/atoms/jl-button.css?raw
2
- var jl_button_default = ":host {\n display: inline-flex;\n vertical-align: middle;\n --height: var(--jl-control-md);\n --pad: 14px;\n --font-size: var(--jl-font-md);\n --radius: var(--jl-radius-sm);\n}\n\n:host([size=\"sm\"]) {\n --height: var(--jl-control-sm);\n --pad: 11px;\n --font-size: var(--jl-font-xs);\n}\n\n:host([size=\"lg\"]) {\n --height: var(--jl-control-lg);\n --pad: 18px;\n --font-size: 15px;\n --radius: var(--jl-radius);\n}\n\n:host([block]) {\n display: flex;\n}\n\nbutton {\n display: inline-flex;\n flex: 1;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: var(--height);\n padding: 0 var(--pad);\n border: 1px solid var(--jl-line-strong);\n border-radius: var(--radius);\n background: var(--jl-surface);\n color: var(--jl-text);\n font-size: var(--font-size);\n font-weight: 600;\n line-height: 1;\n white-space: nowrap;\n cursor: pointer;\n transition:\n background var(--jl-fast) var(--jl-ease),\n border-color var(--jl-fast) var(--jl-ease),\n color var(--jl-fast) var(--jl-ease);\n}\n\n:host([icon-only]) button {\n width: var(--height);\n padding: 0;\n}\n\nbutton:hover {\n background: var(--jl-surface-2);\n}\n\nbutton:active {\n background: var(--jl-surface-3);\n}\n\n:host([variant=\"primary\"]) button {\n border-color: transparent;\n background: var(--jl-accent);\n color: var(--jl-on-accent);\n}\n\n:host([variant=\"primary\"]) button:hover {\n background: var(--jl-accent-strong);\n}\n\n:host([variant=\"ghost\"]) button {\n border-color: transparent;\n background: transparent;\n color: var(--jl-accent);\n}\n\n:host([variant=\"ghost\"]) button:hover {\n background: var(--jl-accent-soft);\n}\n\n:host([variant=\"danger\"]) button {\n border-color: transparent;\n background: var(--jl-danger);\n color: var(--jl-on-danger);\n}\n\n:host([variant=\"danger\"]) button:hover {\n background: color-mix(in srgb, var(--jl-danger) 86%, var(--jl-text));\n}\n\n:host([loading]) button {\n cursor: progress;\n}\n\nbutton:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n";
2
+ var jl_button_default = ":host {\n display: inline-flex;\n vertical-align: middle;\n --height: var(--jl-control-md);\n --pad: 14px;\n --font-size: var(--jl-font-md);\n --radius: var(--jl-radius-sm);\n}\n\n:host([size=\"sm\"]) {\n --height: var(--jl-control-sm);\n --pad: 11px;\n --font-size: var(--jl-font-xs);\n}\n\n:host([size=\"lg\"]) {\n --height: var(--jl-control-lg);\n --pad: 18px;\n --font-size: 15px;\n --radius: var(--jl-radius);\n}\n\n:host([block]) {\n display: flex;\n}\n\n/* Moves between the button and the link: its children are laid out by whichever holds it. */\n.content {\n display: contents;\n}\n\n.base {\n display: inline-flex;\n flex: 1;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: var(--height);\n padding: 0 var(--pad);\n border: 1px solid var(--jl-line-strong);\n border-radius: var(--radius);\n background: var(--jl-surface);\n color: var(--jl-text);\n font-size: var(--font-size);\n font-weight: 600;\n line-height: 1;\n text-decoration: none;\n white-space: nowrap;\n cursor: pointer;\n transition:\n background var(--jl-fast) var(--jl-ease),\n border-color var(--jl-fast) var(--jl-ease),\n color var(--jl-fast) var(--jl-ease);\n}\n\n:host([icon-only]) .base {\n width: var(--height);\n padding: 0;\n}\n\n.base:hover {\n background: var(--jl-surface-2);\n}\n\n.base:active {\n background: var(--jl-surface-3);\n}\n\n:host([variant=\"primary\"]) .base {\n border-color: transparent;\n background: var(--jl-accent);\n color: var(--jl-on-accent);\n}\n\n:host([variant=\"primary\"]) .base:hover {\n background: var(--jl-accent-strong);\n}\n\n:host([variant=\"ghost\"]) .base {\n border-color: transparent;\n background: transparent;\n color: var(--jl-accent);\n}\n\n:host([variant=\"ghost\"]) .base:hover {\n background: var(--jl-accent-soft);\n}\n\n:host([variant=\"danger\"]) .base {\n border-color: transparent;\n background: var(--jl-danger);\n color: var(--jl-on-danger);\n}\n\n:host([variant=\"danger\"]) .base:hover {\n background: color-mix(in srgb, var(--jl-danger) 86%, var(--jl-text));\n}\n\n:host([loading]) .base {\n cursor: progress;\n}\n\n.base:disabled,\n.base[aria-disabled=\"true\"] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n";
3
3
  export { jl_button_default as default };
@@ -6,6 +6,7 @@ export declare const BUTTON_TYPES: readonly ButtonType[];
6
6
  /**
7
7
  * A button. Its text is the `label` (or the slotted content); with only an `icon`, its `hint` names it.
8
8
  * Listen to `press`: it fires only while the button can be pressed. `type="submit"` submits the surrounding form.
9
+ * With an `href` it is a link that looks the same: it opens the address, and `press` still fires.
9
10
  */
10
11
  export declare class JlButton extends JlElement {
11
12
  static readonly selector = "jl-button";
@@ -56,12 +57,30 @@ export declare class JlButton extends JlElement {
56
57
  get(): boolean;
57
58
  set(setter: boolean | ((prevState: boolean) => boolean)): void;
58
59
  }>>;
60
+ /** An address to open: the button becomes a link, for navigation that should open in a new tab when asked. */
61
+ readonly href: Readonly<Readonly<{
62
+ get(): string;
63
+ set(setter: string | ((prevState: string) => string)): void;
64
+ }>>;
65
+ /** Where the link opens (`_blank` for a new tab), with an `href`. */
66
+ readonly target: Readonly<Readonly<{
67
+ get(): string;
68
+ set(setter: string | ((prevState: string) => string)): void;
69
+ }>>;
59
70
  private readonly _internals;
60
71
  private readonly _refs;
61
72
  focus(options?: FocusOptions): void;
62
73
  templateHtml(): Node;
63
74
  templateCss(): string;
64
75
  onConnect(): void;
76
+ private canPress;
77
+ /** The element that takes focus and clicks: the link with an `href`, the button otherwise. */
78
+ private control;
79
+ /**
80
+ * Moves the content into the link or back into the button. A disabled link loses its address, so it can be
81
+ * neither followed nor focused, and says it is disabled.
82
+ */
83
+ private renderLink;
65
84
  private actOnForm;
66
85
  private renderIcon;
67
86
  private renderSize;
@@ -2,11 +2,12 @@ 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";
5
6
  import { JlIcon } from "./jl-icon.js";
6
7
  import jl_button_default from "./jl-button.css_raw.js";
7
8
  import { JlSpinner } from "./jl-spinner.js";
8
9
  import { css } from "@jadis/core";
9
- import { jsx, jsxs } from "@jadis/core/jsx-runtime";
10
+ import { Fragment, jsx, jsxs } from "@jadis/core/jsx-runtime";
10
11
  // src/atoms/jl-button.tsx
11
12
  var BUTTON_VARIANTS = [
12
13
  "secondary",
@@ -24,9 +25,13 @@ var ICON_SIZES = {
24
25
  md: 16,
25
26
  sm: 14
26
27
  };
28
+ var NEW_TAB = "_blank";
29
+ /** A page opened in a new tab gets no handle on this one. */
30
+ var SAFE_REL = "noopener noreferrer";
27
31
  /**
28
32
  * A button. Its text is the `label` (or the slotted content); with only an `icon`, its `hint` names it.
29
33
  * Listen to `press`: it fires only while the button can be pressed. `type="submit"` submits the surrounding form.
34
+ * With an `href` it is a link that looks the same: it opens the address, and `press` still fires.
30
35
  */
31
36
  var JlButton = class extends JlElement {
32
37
  static selector = "jl-button";
@@ -49,6 +54,7 @@ var JlButton = class extends JlElement {
49
54
  });
50
55
  disabled = this.useChange(false, (value) => {
51
56
  this._refs.button.disabled = value;
57
+ this.renderLink();
52
58
  this.reflect("disabled", value);
53
59
  }, { attribute: "disabled" });
54
60
  /** Shows a spinner in place of the icon and ignores presses, while the work it started runs. */
@@ -56,42 +62,57 @@ var JlButton = class extends JlElement {
56
62
  this._refs.spinner.hidden = !value;
57
63
  this._refs.start.hidden = value || this.icon.get() === "";
58
64
  this._refs.button.toggleAttribute("aria-busy", value);
65
+ this._refs.link.toggleAttribute("aria-busy", value);
59
66
  this.reflect("loading", value);
60
67
  }, { attribute: "loading" });
61
68
  /** The tooltip; also the button's name for screen readers when it only has an icon. */
62
69
  hint = this.useChange("", () => this.renderLabel(), { attribute: "hint" });
63
70
  /** Takes the whole width of its container. */
64
71
  block = this.useChange(false, (value) => this.reflect("block", value), { attribute: "block" });
72
+ /** An address to open: the button becomes a link, for navigation that should open in a new tab when asked. */
73
+ href = this.useChange("", () => this.renderLink(), { attribute: "href" });
74
+ /** Where the link opens (`_blank` for a new tab), with an `href`. */
75
+ target = this.useChange("", () => this.renderLink(), { attribute: "target" });
65
76
  _internals = this.attachInternals();
66
77
  _refs = this.useRefs((ref) => ({
67
78
  button: ref("button"),
79
+ content: ref(".content"),
68
80
  end: ref(".end"),
69
81
  label: ref(".text"),
82
+ link: ref("a"),
70
83
  slot: ref("slot"),
71
84
  spinner: ref("jl-spinner"),
72
85
  start: ref(".start")
73
86
  }));
74
87
  focus(options) {
75
- this._refs.button.focus(options);
88
+ this.control().focus(options);
76
89
  }
77
90
  templateHtml() {
78
- return /* @__PURE__ */ jsxs("button", {
91
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
92
+ class: "base",
79
93
  type: "button",
80
94
  attrs: { part: "base" },
81
- children: [
82
- /* @__PURE__ */ jsx(JlSpinner, { hidden: true }),
83
- /* @__PURE__ */ jsx(JlIcon, {
84
- class: "start",
85
- hidden: true
86
- }),
87
- /* @__PURE__ */ jsx("span", { class: "text" }),
88
- /* @__PURE__ */ jsx("slot", {}),
89
- /* @__PURE__ */ jsx(JlIcon, {
90
- class: "end",
91
- hidden: true
92
- })
93
- ]
94
- });
95
+ children: /* @__PURE__ */ jsxs("span", {
96
+ class: "content",
97
+ children: [
98
+ /* @__PURE__ */ jsx(JlSpinner, { hidden: true }),
99
+ /* @__PURE__ */ jsx(JlIcon, {
100
+ class: "start",
101
+ hidden: true
102
+ }),
103
+ /* @__PURE__ */ jsx("span", { class: "text" }),
104
+ /* @__PURE__ */ jsx("slot", {}),
105
+ /* @__PURE__ */ jsx(JlIcon, {
106
+ class: "end",
107
+ hidden: true
108
+ })
109
+ ]
110
+ })
111
+ }), /* @__PURE__ */ jsx("a", {
112
+ class: "base",
113
+ hidden: true,
114
+ attrs: { part: "base" }
115
+ })] });
95
116
  }
96
117
  templateCss() {
97
118
  return css`${BASE_STYLES}${jl_button_default}`;
@@ -99,10 +120,43 @@ var JlButton = class extends JlElement {
99
120
  onConnect() {
100
121
  this.on(this._refs.slot, "slotchange", () => this.renderLabel());
101
122
  this.on(this._refs.button, "click", () => {
102
- if (this.disabled.get() || this.loading.get()) return;
123
+ if (!this.canPress()) return;
103
124
  this.events.emit("press");
104
125
  this.actOnForm();
105
126
  });
127
+ this.on(this._refs.link, "click", (event) => {
128
+ if (!this.canPress()) {
129
+ event.preventDefault();
130
+ return;
131
+ }
132
+ this.events.emit("press");
133
+ });
134
+ }
135
+ canPress() {
136
+ return !(this.disabled.get() || this.loading.get());
137
+ }
138
+ /** The element that takes focus and clicks: the link with an `href`, the button otherwise. */
139
+ control() {
140
+ return this.href.get() === "" ? this._refs.button : this._refs.link;
141
+ }
142
+ /**
143
+ * Moves the content into the link or back into the button. A disabled link loses its address, so it can be
144
+ * neither followed nor focused, and says it is disabled.
145
+ */
146
+ renderLink() {
147
+ const { button, content, link } = this._refs;
148
+ const href = this.href.get();
149
+ const isLink = href !== "";
150
+ const target = this.target.get();
151
+ const off = isLink && this.disabled.get();
152
+ this.control().append(content);
153
+ button.hidden = isLink;
154
+ link.hidden = !isLink;
155
+ setOrRemove(link, "href", isLink && !off ? href : "");
156
+ setOrRemove(link, "target", target);
157
+ setOrRemove(link, "rel", target === NEW_TAB ? SAFE_REL : "");
158
+ setOrRemove(link, "role", off ? "link" : "");
159
+ setOrRemove(link, "aria-disabled", off ? "true" : "");
106
160
  }
107
161
  actOnForm() {
108
162
  const form = this._internals.form;
@@ -133,13 +187,11 @@ var JlButton = class extends JlElement {
133
187
  const iconOnly = label === "" && !this.hasSlottedContent();
134
188
  this._refs.label.textContent = label;
135
189
  this._refs.label.hidden = label === "";
136
- this._refs.button.title = hint;
137
190
  this.reflect("icon-only", iconOnly);
138
- if (iconOnly && hint !== "") {
139
- this._refs.button.setAttribute("aria-label", hint);
140
- return;
191
+ for (const control of [this._refs.button, this._refs.link]) {
192
+ setOrRemove(control, "title", hint);
193
+ setOrRemove(control, "aria-label", iconOnly ? hint : "");
141
194
  }
142
- this._refs.button.removeAttribute("aria-label");
143
195
  }
144
196
  };
145
197
  JlButton.register();
@@ -1,3 +1,3 @@
1
1
  // src/atoms/jl-chip.css?raw
2
- var jl_chip_default = ":host {\n display: inline-flex;\n max-width: 100%;\n vertical-align: middle;\n --height: 28px;\n --pad: 10px;\n --font-size: var(--jl-font-sm);\n --dismiss: 20px;\n}\n\n:host([size=\"sm\"]) {\n --height: 24px;\n --pad: 8px;\n --font-size: var(--jl-font-xs);\n --dismiss: 18px;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n height: var(--height);\n border: 1px solid var(--jl-line-strong);\n border-radius: var(--jl-radius-pill);\n background: var(--jl-surface);\n color: var(--jl-text-2);\n font-size: var(--font-size);\n font-weight: 600;\n line-height: 1;\n white-space: nowrap;\n transition:\n background var(--jl-fast) var(--jl-ease),\n border-color var(--jl-fast) var(--jl-ease),\n color var(--jl-fast) var(--jl-ease);\n}\n\n.main {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n height: 100%;\n padding: 0 var(--pad);\n border-radius: inherit;\n}\n\n.label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.label:empty {\n display: none;\n}\n\n:host([removable]) .main {\n padding-right: 4px;\n}\n\n:host([selectable]) .main {\n cursor: pointer;\n}\n\n:host([selectable]:not([disabled])) .chip:hover {\n background: var(--jl-surface-2);\n}\n\n:host([selected]) .chip,\n:host([selected][selectable]:not([disabled])) .chip:hover {\n border-color: var(--jl-accent-line);\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n/* The ring goes around the whole chip, which the main part fills. */\n.main:focus-visible {\n box-shadow: none;\n}\n\n.chip:has(.main:focus-visible) {\n box-shadow: var(--jl-focus-ring);\n}\n\n.dismiss {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--dismiss);\n height: var(--dismiss);\n margin-right: 3px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--jl-muted);\n cursor: pointer;\n}\n\n.dismiss:hover {\n background: var(--jl-surface-3);\n color: var(--jl-text);\n}\n\n:host([selected]) .dismiss {\n color: var(--jl-accent);\n}\n\n:host([selected]) .dismiss:hover {\n background: color-mix(in srgb, var(--jl-accent) 14%, transparent);\n color: var(--jl-accent-strong);\n}\n\n:host([disabled]) .chip {\n opacity: 0.5;\n}\n\n:host([disabled]) .main,\n:host([disabled]) .dismiss {\n cursor: not-allowed;\n}\n\n:host([disabled]) .dismiss:hover {\n background: transparent;\n}\n";
2
+ var jl_chip_default = ":host {\n display: inline-flex;\n max-width: 100%;\n vertical-align: middle;\n --height: 28px;\n --pad: 10px;\n --font-size: var(--jl-font-sm);\n --dismiss: 20px;\n}\n\n:host([size=\"sm\"]) {\n --height: 24px;\n --pad: 8px;\n --font-size: var(--jl-font-xs);\n --dismiss: 18px;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n height: var(--height);\n border: 1px solid var(--jl-line-strong);\n border-radius: var(--jl-radius-pill);\n background: var(--jl-surface);\n color: var(--jl-text-2);\n font-size: var(--font-size);\n font-weight: 600;\n line-height: 1;\n white-space: nowrap;\n transition:\n background var(--jl-fast) var(--jl-ease),\n border-color var(--jl-fast) var(--jl-ease),\n color var(--jl-fast) var(--jl-ease);\n}\n\n.main {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n height: 100%;\n padding: 0 var(--pad);\n border-radius: inherit;\n}\n\n/* A line box taller than the chip's own line-height of 1: the accents of É, Â, Ö stay inside what overflow clips. */\n.label {\n overflow: hidden;\n line-height: 1.4;\n text-overflow: ellipsis;\n}\n\n.label:empty {\n display: none;\n}\n\n:host([removable]) .main {\n padding-right: 4px;\n}\n\n:host([selectable]) .main {\n cursor: pointer;\n}\n\n:host([selectable]:not([disabled])) .chip:hover {\n background: var(--jl-surface-2);\n}\n\n:host([selected]) .chip,\n:host([selected][selectable]:not([disabled])) .chip:hover {\n border-color: var(--jl-accent-line);\n background: var(--jl-accent-soft);\n color: var(--jl-accent);\n}\n\n/* The ring goes around the whole chip, which the main part fills. */\n.main:focus-visible {\n box-shadow: none;\n}\n\n.chip:has(.main:focus-visible) {\n box-shadow: var(--jl-focus-ring);\n}\n\n.dismiss {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: var(--dismiss);\n height: var(--dismiss);\n margin-right: 3px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--jl-muted);\n cursor: pointer;\n}\n\n.dismiss:hover {\n background: var(--jl-surface-3);\n color: var(--jl-text);\n}\n\n:host([selected]) .dismiss {\n color: var(--jl-accent);\n}\n\n:host([selected]) .dismiss:hover {\n background: color-mix(in srgb, var(--jl-accent) 14%, transparent);\n color: var(--jl-accent-strong);\n}\n\n:host([disabled]) .chip {\n opacity: 0.5;\n}\n\n:host([disabled]) .main,\n:host([disabled]) .dismiss {\n cursor: not-allowed;\n}\n\n:host([disabled]) .dismiss:hover {\n background: transparent;\n}\n";
3
3
  export { jl_chip_default as default };
@@ -34,6 +34,11 @@ export declare class JlInput extends JlFormControl {
34
34
  get(): string;
35
35
  set(setter: string | ((prevState: string) => string)): void;
36
36
  }>>;
37
+ /** The keyboard a phone shows for the field (`numeric`, `decimal`, `tel`…), as a native input's `inputmode`. */
38
+ readonly inputmode: Readonly<Readonly<{
39
+ get(): string;
40
+ set(setter: string | ((prevState: string) => string)): void;
41
+ }>>;
37
42
  readonly min: Readonly<Readonly<{
38
43
  get(): string;
39
44
  set(setter: string | ((prevState: string) => string)): void;
@@ -50,6 +50,8 @@ var JlInput = class extends JlFormControl {
50
50
  /** The field's name for screen readers, when no visible label names it. */
51
51
  label = this.useChange("", (value) => this.setNative("aria-label", value), { attribute: "label" });
52
52
  autocomplete = this.useChange("", (value) => this.setNative("autocomplete", value), { attribute: "autocomplete" });
53
+ /** The keyboard a phone shows for the field (`numeric`, `decimal`, `tel`…), as a native input's `inputmode`. */
54
+ inputmode = this.useChange("", (value) => this.setNative("inputmode", value), { attribute: "inputmode" });
53
55
  min = this.useChange("", (value) => this.setNative("min", value), { attribute: "min" });
54
56
  max = this.useChange("", (value) => this.setNative("max", value), { attribute: "max" });
55
57
  step = this.useChange("", (value) => this.setNative("step", value), { attribute: "step" });
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { computePosition, followAnchor, PLACEMENTS, placeFloating } from './lib/
6
6
  export { COMMON_ICONS } from './lib/icon-set';
7
7
  export { hasIcon, iconElement, iconNames, registerIcons } from './lib/icons';
8
8
  export { CONTROL_SIZES, TONE_ICON_FILLED, TONE_ICONS, TONES } from './lib/options';
9
+ export { formatDuration, formatRelativeTime } from './lib/time';
9
10
  export { adoptTokens } from './lib/tokens';
10
11
  export { BASE_STYLES, CONTROL_STYLES, FLOATING_STYLES, TOKEN_STYLES } from './styles/shared';
11
12
  export type * from './types/calendar.types';
@@ -16,9 +17,11 @@ export type * from './types/highlight.types';
16
17
  export type * from './types/hotkey.types';
17
18
  export type * from './types/jl-accordion.types';
18
19
  export type * from './types/jl-avatar.types';
20
+ export type * from './types/jl-badge.types';
19
21
  export type * from './types/jl-breadcrumb.types';
20
22
  export type * from './types/jl-button.types';
21
23
  export type * from './types/jl-card.types';
24
+ export type * from './types/jl-chip-group.types';
22
25
  export type * from './types/jl-chip.types';
23
26
  export type * from './types/jl-combobox.types';
24
27
  export type * from './types/jl-command-palette.types';
@@ -31,8 +34,10 @@ export type * from './types/jl-field.types';
31
34
  export type * from './types/jl-flow.types';
32
35
  export type * from './types/jl-input.types';
33
36
  export type * from './types/jl-link.types';
37
+ export type * from './types/jl-load-state.types';
34
38
  export type * from './types/jl-menu.types';
35
39
  export type * from './types/jl-navbar.types';
40
+ export type * from './types/jl-page.types';
36
41
  export type * from './types/jl-progress.types';
37
42
  export type * from './types/jl-radio-group.types';
38
43
  export type * from './types/jl-segmented.types';
@@ -44,6 +49,7 @@ export type * from './types/jl-split-view.types';
44
49
  export type * from './types/jl-stat.types';
45
50
  export type * from './types/jl-steps.types';
46
51
  export type * from './types/jl-switch.types';
52
+ export type * from './types/jl-tab-bar.types';
47
53
  export type * from './types/jl-table.types';
48
54
  export type * from './types/jl-tabs.types';
49
55
  export type * from './types/jl-timeline.types';
@@ -78,11 +84,13 @@ export * from './atoms/jl-switch';
78
84
  export * from './atoms/jl-textarea';
79
85
  export * from './molecules/jl-accordion-item';
80
86
  export * from './molecules/jl-accordion';
87
+ export * from './molecules/jl-account-button';
81
88
  export * from './molecules/jl-alert';
82
89
  export * from './molecules/jl-avatar-group';
83
90
  export * from './molecules/jl-breadcrumb';
84
91
  export * from './molecules/jl-calendar';
85
92
  export * from './molecules/jl-card';
93
+ export * from './molecules/jl-chip-group';
86
94
  export * from './molecules/jl-code-block';
87
95
  export * from './molecules/jl-combobox';
88
96
  export * from './molecules/jl-copy-button';
@@ -91,11 +99,13 @@ export * from './molecules/jl-empty';
91
99
  export * from './molecules/jl-field';
92
100
  export * from './molecules/jl-file-drop';
93
101
  export * from './molecules/jl-list-item';
102
+ export * from './molecules/jl-load-state';
94
103
  export * from './molecules/jl-menu';
95
104
  export * from './molecules/jl-number-input';
96
105
  export * from './molecules/jl-pagination';
97
106
  export * from './molecules/jl-popover';
98
107
  export * from './molecules/jl-radio-group';
108
+ export * from './molecules/jl-search-button';
99
109
  export * from './molecules/jl-search';
100
110
  export * from './molecules/jl-segmented';
101
111
  export * from './molecules/jl-stat';
@@ -114,8 +124,10 @@ export * from './organisms/jl-flow';
114
124
  export * from './organisms/jl-navbar';
115
125
  export * from './organisms/jl-page-header';
116
126
  export * from './organisms/jl-side-nav';
127
+ export * from './organisms/jl-tab-bar';
117
128
  export * from './organisms/jl-table';
118
129
  export * from './organisms/jl-toaster';
119
130
  export * from './organisms/jl-tree';
120
131
  export * from './templates/jl-app-shell';
132
+ export * from './templates/jl-page';
121
133
  export * from './templates/jl-split-view';
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import { PLACEMENTS, computePosition, followAnchor, placeFloating } from "./lib/
8
8
  import { COMMON_ICONS } from "./lib/icon-set.js";
9
9
  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
+ import { formatDuration, formatRelativeTime } from "./lib/time.js";
11
12
  import { JlIcon } from "./atoms/jl-icon.js";
12
13
  import { AVATAR_SHAPES, AVATAR_SIZES, AVATAR_STATUSES, JlAvatar } from "./atoms/jl-avatar.js";
13
14
  import { JlBadge } from "./atoms/jl-badge.js";
@@ -29,11 +30,13 @@ import { JlSwitch, SWITCH_SIZES } from "./atoms/jl-switch.js";
29
30
  import { JlTextarea } from "./atoms/jl-textarea.js";
30
31
  import { JlAccordionItem } from "./molecules/jl-accordion-item.js";
31
32
  import { ACCORDION_VARIANTS, JlAccordion } from "./molecules/jl-accordion.js";
33
+ import { JlAccountButton } from "./molecules/jl-account-button.js";
32
34
  import { JlAlert } from "./molecules/jl-alert.js";
33
35
  import { JlAvatarGroup } from "./molecules/jl-avatar-group.js";
34
36
  import { JlBreadcrumb } from "./molecules/jl-breadcrumb.js";
35
37
  import { JlCalendar } from "./molecules/jl-calendar.js";
36
38
  import { CARD_PADDINGS, JlCard } from "./molecules/jl-card.js";
39
+ import { JlChipGroup } from "./molecules/jl-chip-group.js";
37
40
  import { JlCopyButton } from "./molecules/jl-copy-button.js";
38
41
  import { CODE_LANGUAGES, JlCodeBlock } from "./molecules/jl-code-block.js";
39
42
  import { JlCombobox } from "./molecules/jl-combobox.js";
@@ -42,11 +45,13 @@ import { EMPTY_SIZES, JlEmpty } from "./molecules/jl-empty.js";
42
45
  import { FIELD_ORIENTATIONS, JlField } from "./molecules/jl-field.js";
43
46
  import { JlFileDrop } from "./molecules/jl-file-drop.js";
44
47
  import { JlListItem } from "./molecules/jl-list-item.js";
48
+ import { JlLoadState, LOAD_SKELETONS, LOAD_STATES } from "./molecules/jl-load-state.js";
45
49
  import { JlMenu } from "./molecules/jl-menu.js";
46
50
  import { JlNumberInput } from "./molecules/jl-number-input.js";
47
51
  import { JlPagination } from "./molecules/jl-pagination.js";
48
52
  import { JlPopover } from "./molecules/jl-popover.js";
49
53
  import { JlRadioGroup, RADIO_GROUP_ORIENTATIONS, RADIO_GROUP_VARIANTS } from "./molecules/jl-radio-group.js";
54
+ import { JlSearchButton } from "./molecules/jl-search-button.js";
50
55
  import { JlSearch } from "./molecules/jl-search.js";
51
56
  import { JlSegmented } from "./molecules/jl-segmented.js";
52
57
  import { JlStat, STAT_TRENDS } from "./molecules/jl-stat.js";
@@ -59,15 +64,17 @@ import { JlToast, TOAST_TONES } from "./molecules/jl-toast.js";
59
64
  import { JlTooltip } from "./molecules/jl-tooltip.js";
60
65
  import { JlCommandPalette } from "./organisms/jl-command-palette.js";
61
66
  import { DIALOG_SIZES, JlDialog } from "./organisms/jl-dialog.js";
62
- import { CONFIRM_TONES, JlConfirm, confirmDialog } from "./organisms/jl-confirm.js";
67
+ import { CONFIRM_TONES, JlConfirm, confirmDialog, guardLeave } from "./organisms/jl-confirm.js";
63
68
  import { DRAWER_PLACEMENTS, DRAWER_SIZES, JlDrawer } from "./organisms/jl-drawer.js";
64
69
  import { JlFlow } from "./organisms/jl-flow.js";
65
70
  import { JlNavbar } from "./organisms/jl-navbar.js";
66
71
  import { JlPageHeader } from "./organisms/jl-page-header.js";
67
72
  import { JlSideNav } from "./organisms/jl-side-nav.js";
73
+ import { JlTabBar } from "./organisms/jl-tab-bar.js";
68
74
  import { JlTable, TABLE_SORT_DIRECTIONS } from "./organisms/jl-table.js";
69
75
  import { JlToaster, TOASTER_PLACEMENTS, toast } from "./organisms/jl-toaster.js";
70
76
  import { JlTree } from "./organisms/jl-tree.js";
71
77
  import { JlAppShell } from "./templates/jl-app-shell.js";
78
+ import { JlPage, PAGE_WIDTHS } from "./templates/jl-page.js";
72
79
  import { JlSplitView, SPLIT_ORIENTATIONS } from "./templates/jl-split-view.js";
73
- 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, JlAlert, JlAppShell, JlAvatar, JlAvatarGroup, JlBadge, JlBreadcrumb, JlButton, JlCalendar, JlCard, JlCheckbox, JlChip, JlCodeBlock, JlCombobox, JlCommandPalette, JlConfirm, JlCopyButton, JlDatePicker, JlDialog, JlDivider, JlDrawer, JlElement, JlEmpty, JlField, JlFileDrop, JlFlow, JlFormControl, JlIcon, JlInput, JlKbd, JlLink, JlListItem, JlMenu, JlNavbar, JlNumberInput, JlPageHeader, JlPagination, JlPopover, JlProgress, JlProgressRing, JlRadioGroup, JlRating, JlSearch, JlSegmented, JlSelect, JlSideNav, JlSkeleton, JlSlider, JlSpinner, JlSplitView, JlStat, JlSteps, JlSwitch, JlTabPanel, JlTable, JlTabs, JlTagInput, JlTextarea, JlTimeline, JlToast, JlToaster, JlTooltip, JlTree, LINK_VARIANTS, 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, hasIcon, iconElement, iconNames, jsonOf, oneOf, placeFloating, registerIcons, toast };
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 };
@@ -7,3 +7,8 @@ export declare const oneOf: <Value extends string>(allowed: readonly Value[], fa
7
7
  export declare const jsonOf: <Value>(fallback: Value) => (value: string | null) => Value;
8
8
  /** A number attribute kept within bounds; a missing or unreadable one gives the fallback. */
9
9
  export declare const clampedNumber: (fallback: number, min: number, max: number) => (value: string | null) => number;
10
+ /**
11
+ * An attribute holding a list of strings, as HTML writes it: a JSON list (`'["a","b"]'`), or one plain value
12
+ * (`open`) for the common case of a single one. Empty or unreadable gives an empty list.
13
+ */
14
+ export declare const stringList: (value: string | null) => string[];
@@ -19,4 +19,16 @@ var clampedNumber = (fallback, min, max) => (value) => {
19
19
  if (Number.isNaN(parsed)) return fallback;
20
20
  return Math.min(max, Math.max(min, parsed));
21
21
  };
22
- export { clampedNumber, jsonOf, oneOf };
22
+ var LIST_START = "[";
23
+ /**
24
+ * An attribute holding a list of strings, as HTML writes it: a JSON list (`'["a","b"]'`), or one plain value
25
+ * (`open`) for the common case of a single one. Empty or unreadable gives an empty list.
26
+ */
27
+ var stringList = (value) => {
28
+ const text = value?.trim() ?? "";
29
+ if (text === "") return [];
30
+ if (!text.startsWith(LIST_START)) return [text];
31
+ const parsed = jsonOf([])(text);
32
+ return Array.isArray(parsed) ? parsed.map(String) : [];
33
+ };
34
+ export { clampedNumber, jsonOf, oneOf, stringList };
@@ -0,0 +1,10 @@
1
+ /**
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.
4
+ */
5
+ export declare function formatDuration(milliseconds: number, locale?: string): string;
6
+ /**
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".
9
+ */
10
+ export declare function formatRelativeTime(date: Date | number | string, now: Date | number, locale?: string): string;