@syware/jlib 0.0.0-stage → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +133 -2
- package/dist/all.d.ts +1 -0
- package/dist/all.js +75 -0
- package/dist/atoms/jl-avatar.css_raw.js +3 -0
- package/dist/atoms/jl-avatar.d.ts +52 -0
- package/dist/atoms/jl-avatar.js +167 -0
- package/dist/atoms/jl-badge.css_raw.js +3 -0
- package/dist/atoms/jl-badge.d.ts +32 -0
- package/dist/atoms/jl-badge.js +60 -0
- package/dist/atoms/jl-button.css_raw.js +3 -0
- package/dist/atoms/jl-button.d.ts +70 -0
- package/dist/atoms/jl-button.js +146 -0
- package/dist/atoms/jl-checkbox.css_raw.js +3 -0
- package/dist/atoms/jl-checkbox.d.ts +61 -0
- package/dist/atoms/jl-checkbox.js +149 -0
- package/dist/atoms/jl-chip.css_raw.js +3 -0
- package/dist/atoms/jl-chip.d.ts +59 -0
- package/dist/atoms/jl-chip.js +164 -0
- package/dist/atoms/jl-divider.css_raw.js +3 -0
- package/dist/atoms/jl-divider.d.ts +26 -0
- package/dist/atoms/jl-divider.js +59 -0
- package/dist/atoms/jl-icon.css_raw.js +3 -0
- package/dist/atoms/jl-icon.d.ts +25 -0
- package/dist/atoms/jl-icon.js +41 -0
- package/dist/atoms/jl-input.css_raw.js +3 -0
- package/dist/atoms/jl-input.d.ts +112 -0
- package/dist/atoms/jl-input.js +202 -0
- package/dist/atoms/jl-kbd.css_raw.js +3 -0
- package/dist/atoms/jl-kbd.d.ts +17 -0
- package/dist/atoms/jl-kbd.js +62 -0
- package/dist/atoms/jl-link.css_raw.js +3 -0
- package/dist/atoms/jl-link.d.ts +37 -0
- package/dist/atoms/jl-link.js +86 -0
- package/dist/atoms/jl-progress-ring.css_raw.js +3 -0
- package/dist/atoms/jl-progress-ring.d.ts +49 -0
- package/dist/atoms/jl-progress-ring.js +132 -0
- package/dist/atoms/jl-progress.css_raw.js +3 -0
- package/dist/atoms/jl-progress.d.ts +43 -0
- package/dist/atoms/jl-progress.js +109 -0
- package/dist/atoms/jl-rating.css_raw.js +3 -0
- package/dist/atoms/jl-rating.d.ts +73 -0
- package/dist/atoms/jl-rating.js +184 -0
- package/dist/atoms/jl-select.css_raw.js +3 -0
- package/dist/atoms/jl-select.d.ts +70 -0
- package/dist/atoms/jl-select.js +146 -0
- package/dist/atoms/jl-skeleton.css_raw.js +3 -0
- package/dist/atoms/jl-skeleton.d.ts +34 -0
- package/dist/atoms/jl-skeleton.js +63 -0
- package/dist/atoms/jl-slider.css_raw.js +3 -0
- package/dist/atoms/jl-slider.d.ts +65 -0
- package/dist/atoms/jl-slider.js +143 -0
- package/dist/atoms/jl-spinner.css_raw.js +3 -0
- package/dist/atoms/jl-spinner.d.ts +16 -0
- package/dist/atoms/jl-spinner.js +26 -0
- package/dist/atoms/jl-switch.css_raw.js +3 -0
- package/dist/atoms/jl-switch.d.ts +57 -0
- package/dist/atoms/jl-switch.js +125 -0
- package/dist/atoms/jl-textarea.css_raw.js +3 -0
- package/dist/atoms/jl-textarea.d.ts +81 -0
- package/dist/atoms/jl-textarea.js +148 -0
- package/dist/base/jl-element.d.ts +16 -0
- package/dist/base/jl-element.js +35 -0
- package/dist/base/jl-form-control.d.ts +29 -0
- package/dist/base/jl-form-control.js +44 -0
- package/dist/index.d.ts +119 -0
- package/dist/index.js +72 -0
- package/dist/lib/arrow.d.ts +6 -0
- package/dist/lib/arrow.js +15 -0
- package/dist/lib/attributes.d.ts +9 -0
- package/dist/lib/attributes.js +22 -0
- package/dist/lib/avatar.d.ts +11 -0
- package/dist/lib/avatar.js +37 -0
- package/dist/lib/calendar.d.ts +48 -0
- package/dist/lib/calendar.js +166 -0
- package/dist/lib/css-length.d.ts +2 -0
- package/dist/lib/css-length.js +8 -0
- package/dist/lib/define.d.ts +9 -0
- package/dist/lib/define.js +9 -0
- package/dist/lib/dom.d.ts +4 -0
- package/dist/lib/dom.js +16 -0
- package/dist/lib/files.d.ts +18 -0
- package/dist/lib/files.js +89 -0
- package/dist/lib/floating.d.ts +13 -0
- package/dist/lib/floating.js +127 -0
- package/dist/lib/fuzzy.d.ts +26 -0
- package/dist/lib/fuzzy.js +149 -0
- package/dist/lib/highlight.d.ts +5 -0
- package/dist/lib/highlight.js +267 -0
- package/dist/lib/hotkey.d.ts +9 -0
- package/dist/lib/hotkey.js +101 -0
- package/dist/lib/icon-set.d.ts +95 -0
- package/dist/lib/icon-set.js +97 -0
- package/dist/lib/icons.d.ts +12 -0
- package/dist/lib/icons.js +39 -0
- package/dist/lib/indicator.d.ts +6 -0
- package/dist/lib/indicator.js +18 -0
- package/dist/lib/keep-in-view.d.ts +5 -0
- package/dist/lib/keep-in-view.js +15 -0
- package/dist/lib/key-shortcut.d.ts +20 -0
- package/dist/lib/key-shortcut.js +100 -0
- package/dist/lib/keycaps.d.ts +8 -0
- package/dist/lib/keycaps.js +162 -0
- package/dist/lib/locale.d.ts +4 -0
- package/dist/lib/locale.js +13 -0
- package/dist/lib/nav-tree.d.ts +9 -0
- package/dist/lib/nav-tree.js +30 -0
- package/dist/lib/numeric.d.ts +20 -0
- package/dist/lib/numeric.js +50 -0
- package/dist/lib/option-filter.d.ts +29 -0
- package/dist/lib/option-filter.js +108 -0
- package/dist/lib/option-groups.d.ts +6 -0
- package/dist/lib/option-groups.js +26 -0
- package/dist/lib/options.d.ts +5 -0
- package/dist/lib/options.js +24 -0
- package/dist/lib/pagination.d.ts +9 -0
- package/dist/lib/pagination.js +52 -0
- package/dist/lib/palette.d.ts +8 -0
- package/dist/lib/palette.js +46 -0
- package/dist/lib/progress.d.ts +20 -0
- package/dist/lib/progress.js +33 -0
- package/dist/lib/rating.d.ts +7 -0
- package/dist/lib/rating.js +26 -0
- package/dist/lib/roving-index.d.ts +10 -0
- package/dist/lib/roving-index.js +32 -0
- package/dist/lib/roving.d.ts +11 -0
- package/dist/lib/roving.js +21 -0
- package/dist/lib/slots.d.ts +2 -0
- package/dist/lib/slots.js +6 -0
- package/dist/lib/sparkline.d.ts +11 -0
- package/dist/lib/sparkline.js +42 -0
- package/dist/lib/split.d.ts +12 -0
- package/dist/lib/split.js +37 -0
- package/dist/lib/surface.d.ts +7 -0
- package/dist/lib/surface.js +28 -0
- package/dist/lib/table.d.ts +30 -0
- package/dist/lib/table.js +110 -0
- package/dist/lib/tags.d.ts +14 -0
- package/dist/lib/tags.js +29 -0
- package/dist/lib/text.d.ts +5 -0
- package/dist/lib/text.js +13 -0
- package/dist/lib/tokens.d.ts +5 -0
- package/dist/lib/tokens.js +15 -0
- package/dist/lib/tree.d.ts +16 -0
- package/dist/lib/tree.js +89 -0
- package/dist/lib/trend.d.ts +3 -0
- package/dist/lib/trend.js +15 -0
- package/dist/lib/trigger.d.ts +11 -0
- package/dist/lib/trigger.js +34 -0
- package/dist/molecules/jl-accordion-item.css_raw.js +3 -0
- package/dist/molecules/jl-accordion-item.d.ts +34 -0
- package/dist/molecules/jl-accordion-item.js +82 -0
- package/dist/molecules/jl-accordion.css_raw.js +3 -0
- package/dist/molecules/jl-accordion.d.ts +27 -0
- package/dist/molecules/jl-accordion.js +61 -0
- package/dist/molecules/jl-alert.css_raw.js +3 -0
- package/dist/molecules/jl-alert.d.ts +38 -0
- package/dist/molecules/jl-alert.js +131 -0
- package/dist/molecules/jl-avatar-group.css_raw.js +3 -0
- package/dist/molecules/jl-avatar-group.d.ts +28 -0
- package/dist/molecules/jl-avatar-group.js +69 -0
- package/dist/molecules/jl-breadcrumb.css_raw.js +3 -0
- package/dist/molecules/jl-breadcrumb.d.ts +35 -0
- package/dist/molecules/jl-breadcrumb.js +126 -0
- package/dist/molecules/jl-calendar.css_raw.js +3 -0
- package/dist/molecules/jl-calendar.d.ts +101 -0
- package/dist/molecules/jl-calendar.js +314 -0
- package/dist/molecules/jl-card.css_raw.js +3 -0
- package/dist/molecules/jl-card.d.ts +46 -0
- package/dist/molecules/jl-card.js +172 -0
- package/dist/molecules/jl-code-block.css_raw.js +3 -0
- package/dist/molecules/jl-code-block.d.ts +44 -0
- package/dist/molecules/jl-code-block.js +106 -0
- package/dist/molecules/jl-combobox.css_raw.js +3 -0
- package/dist/molecules/jl-combobox.d.ts +120 -0
- package/dist/molecules/jl-combobox.js +450 -0
- package/dist/molecules/jl-copy-button.css_raw.js +3 -0
- package/dist/molecules/jl-copy-button.d.ts +31 -0
- package/dist/molecules/jl-copy-button.js +69 -0
- package/dist/molecules/jl-date-picker.css_raw.js +3 -0
- package/dist/molecules/jl-date-picker.d.ts +109 -0
- package/dist/molecules/jl-date-picker.js +322 -0
- package/dist/molecules/jl-empty.css_raw.js +3 -0
- package/dist/molecules/jl-empty.d.ts +32 -0
- package/dist/molecules/jl-empty.js +94 -0
- package/dist/molecules/jl-field.css_raw.js +3 -0
- package/dist/molecules/jl-field.d.ts +49 -0
- package/dist/molecules/jl-field.js +147 -0
- package/dist/molecules/jl-file-drop.css_raw.js +3 -0
- package/dist/molecules/jl-file-drop.d.ts +93 -0
- package/dist/molecules/jl-file-drop.js +366 -0
- package/dist/molecules/jl-list-item.css_raw.js +3 -0
- package/dist/molecules/jl-list-item.d.ts +56 -0
- package/dist/molecules/jl-list-item.js +176 -0
- package/dist/molecules/jl-menu.css_raw.js +3 -0
- package/dist/molecules/jl-menu.d.ts +62 -0
- package/dist/molecules/jl-menu.js +288 -0
- package/dist/molecules/jl-number-input.css_raw.js +3 -0
- package/dist/molecules/jl-number-input.d.ts +81 -0
- package/dist/molecules/jl-number-input.js +220 -0
- package/dist/molecules/jl-pagination.css_raw.js +3 -0
- package/dist/molecules/jl-pagination.d.ts +59 -0
- package/dist/molecules/jl-pagination.js +172 -0
- package/dist/molecules/jl-popover.css_raw.js +3 -0
- package/dist/molecules/jl-popover.d.ts +49 -0
- package/dist/molecules/jl-popover.js +152 -0
- package/dist/molecules/jl-radio-group.css_raw.js +3 -0
- package/dist/molecules/jl-radio-group.d.ts +71 -0
- package/dist/molecules/jl-radio-group.js +202 -0
- package/dist/molecules/jl-search.css_raw.js +3 -0
- package/dist/molecules/jl-search.d.ts +71 -0
- package/dist/molecules/jl-search.js +210 -0
- package/dist/molecules/jl-segmented.css_raw.js +3 -0
- package/dist/molecules/jl-segmented.d.ts +65 -0
- package/dist/molecules/jl-segmented.js +187 -0
- package/dist/molecules/jl-stat.css_raw.js +3 -0
- package/dist/molecules/jl-stat.d.ts +55 -0
- package/dist/molecules/jl-stat.js +169 -0
- package/dist/molecules/jl-steps.css_raw.js +3 -0
- package/dist/molecules/jl-steps.d.ts +44 -0
- package/dist/molecules/jl-steps.js +118 -0
- package/dist/molecules/jl-tab-panel.css_raw.js +3 -0
- package/dist/molecules/jl-tab-panel.d.ts +35 -0
- package/dist/molecules/jl-tab-panel.js +35 -0
- package/dist/molecules/jl-tabs.css_raw.js +3 -0
- package/dist/molecules/jl-tabs.d.ts +51 -0
- package/dist/molecules/jl-tabs.js +198 -0
- package/dist/molecules/jl-tag-input.css_raw.js +3 -0
- package/dist/molecules/jl-tag-input.d.ts +103 -0
- package/dist/molecules/jl-tag-input.js +429 -0
- package/dist/molecules/jl-timeline.css_raw.js +3 -0
- package/dist/molecules/jl-timeline.d.ts +28 -0
- package/dist/molecules/jl-timeline.js +81 -0
- package/dist/molecules/jl-toast.css_raw.js +3 -0
- package/dist/molecules/jl-toast.d.ts +75 -0
- package/dist/molecules/jl-toast.js +274 -0
- package/dist/molecules/jl-tooltip.css_raw.js +3 -0
- package/dist/molecules/jl-tooltip.d.ts +44 -0
- package/dist/molecules/jl-tooltip.js +160 -0
- package/dist/organisms/jl-command-palette.css_raw.js +3 -0
- package/dist/organisms/jl-command-palette.d.ts +60 -0
- package/dist/organisms/jl-command-palette.js +285 -0
- package/dist/organisms/jl-confirm.css_raw.js +3 -0
- package/dist/organisms/jl-confirm.d.ts +56 -0
- package/dist/organisms/jl-confirm.js +132 -0
- package/dist/organisms/jl-dialog.css_raw.js +3 -0
- package/dist/organisms/jl-dialog.d.ts +43 -0
- package/dist/organisms/jl-dialog.js +120 -0
- package/dist/organisms/jl-drawer.css_raw.js +3 -0
- package/dist/organisms/jl-drawer.d.ts +50 -0
- package/dist/organisms/jl-drawer.js +141 -0
- package/dist/organisms/jl-navbar.css_raw.js +3 -0
- package/dist/organisms/jl-navbar.d.ts +32 -0
- package/dist/organisms/jl-navbar.js +121 -0
- package/dist/organisms/jl-page-header.css_raw.js +3 -0
- package/dist/organisms/jl-page-header.d.ts +26 -0
- package/dist/organisms/jl-page-header.js +85 -0
- package/dist/organisms/jl-side-nav.css_raw.js +3 -0
- package/dist/organisms/jl-side-nav.d.ts +60 -0
- package/dist/organisms/jl-side-nav.js +269 -0
- package/dist/organisms/jl-table.css_raw.js +3 -0
- package/dist/organisms/jl-table.d.ts +109 -0
- package/dist/organisms/jl-table.js +318 -0
- package/dist/organisms/jl-toaster.css_raw.js +3 -0
- package/dist/organisms/jl-toaster.d.ts +48 -0
- package/dist/organisms/jl-toaster.js +142 -0
- package/dist/organisms/jl-tree.css_raw.js +3 -0
- package/dist/organisms/jl-tree.d.ts +59 -0
- package/dist/organisms/jl-tree.js +198 -0
- package/dist/styles/base.css_raw.js +3 -0
- package/dist/styles/control.css_raw.js +3 -0
- package/dist/styles/floating.css_raw.js +3 -0
- package/dist/styles/shared.d.ts +8 -0
- package/dist/styles/shared.js +14 -0
- package/dist/styles/tokens.css_raw.js +3 -0
- package/dist/templates/jl-app-shell.css_raw.js +3 -0
- package/dist/templates/jl-app-shell.d.ts +37 -0
- package/dist/templates/jl-app-shell.js +150 -0
- package/dist/templates/jl-split-view.css_raw.js +3 -0
- package/dist/templates/jl-split-view.d.ts +49 -0
- package/dist/templates/jl-split-view.js +149 -0
- package/dist/tokens.css +188 -0
- package/dist/types/calendar.types.d.ts +11 -0
- package/dist/types/files.types.d.ts +23 -0
- package/dist/types/floating.types.d.ts +13 -0
- package/dist/types/fuzzy.types.d.ts +10 -0
- package/dist/types/highlight.types.d.ts +6 -0
- package/dist/types/hotkey.types.d.ts +19 -0
- package/dist/types/jl-accordion.types.d.ts +2 -0
- package/dist/types/jl-avatar.types.d.ts +10 -0
- package/dist/types/jl-breadcrumb.types.d.ts +6 -0
- package/dist/types/jl-button.types.d.ts +3 -0
- package/dist/types/jl-card.types.d.ts +2 -0
- package/dist/types/jl-chip.types.d.ts +1 -0
- package/dist/types/jl-combobox.types.d.ts +8 -0
- package/dist/types/jl-command-palette.types.d.ts +22 -0
- package/dist/types/jl-confirm.types.d.ts +10 -0
- package/dist/types/jl-dialog.types.d.ts +1 -0
- package/dist/types/jl-divider.types.d.ts +2 -0
- package/dist/types/jl-drawer.types.d.ts +4 -0
- package/dist/types/jl-empty.types.d.ts +2 -0
- package/dist/types/jl-field.types.d.ts +2 -0
- package/dist/types/jl-input.types.d.ts +1 -0
- package/dist/types/jl-link.types.d.ts +2 -0
- package/dist/types/jl-menu.types.d.ts +22 -0
- package/dist/types/jl-navbar.types.d.ts +6 -0
- package/dist/types/jl-progress.types.d.ts +3 -0
- package/dist/types/jl-radio-group.types.d.ts +10 -0
- package/dist/types/jl-segmented.types.d.ts +7 -0
- package/dist/types/jl-select.types.d.ts +12 -0
- package/dist/types/jl-side-nav.types.d.ts +17 -0
- package/dist/types/jl-skeleton.types.d.ts +2 -0
- package/dist/types/jl-slider.types.d.ts +5 -0
- package/dist/types/jl-split-view.types.d.ts +2 -0
- package/dist/types/jl-stat.types.d.ts +2 -0
- package/dist/types/jl-steps.types.d.ts +8 -0
- package/dist/types/jl-switch.types.d.ts +1 -0
- package/dist/types/jl-table.types.d.ts +30 -0
- package/dist/types/jl-tabs.types.d.ts +2 -0
- package/dist/types/jl-timeline.types.d.ts +10 -0
- package/dist/types/jl-toast.types.d.ts +2 -0
- package/dist/types/jl-toaster.types.d.ts +23 -0
- package/dist/types/jl-tree.types.d.ts +26 -0
- package/dist/types/key-shortcut.types.d.ts +9 -0
- package/dist/types/keycaps.types.d.ts +7 -0
- package/dist/types/option-filter.types.d.ts +10 -0
- package/dist/types/options.types.d.ts +4 -0
- package/dist/types/pagination.types.d.ts +8 -0
- package/dist/types/roving-index.types.d.ts +2 -0
- package/dist/types/sparkline.types.d.ts +11 -0
- package/package.json +102 -4
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
|
+
import { JlElement } from "../base/jl-element.js";
|
|
3
|
+
import { oneOf } from "../lib/attributes.js";
|
|
4
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
5
|
+
import jl_divider_default from "./jl-divider.css_raw.js";
|
|
6
|
+
import { css } from "@jadis/core";
|
|
7
|
+
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
8
|
+
// src/atoms/jl-divider.tsx
|
|
9
|
+
var DIVIDER_ALIGNS = [
|
|
10
|
+
"center",
|
|
11
|
+
"start",
|
|
12
|
+
"end"
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* A line between groups of content, across or (`vertical`) up and down. A `label` sits on the line: "or",
|
|
16
|
+
* "Today", "Advanced".
|
|
17
|
+
*/
|
|
18
|
+
var JlDivider = class extends JlElement {
|
|
19
|
+
static selector = "jl-divider";
|
|
20
|
+
label = this.useChange("", (value) => {
|
|
21
|
+
this._refs.label.textContent = value;
|
|
22
|
+
this._refs.label.hidden = value === "";
|
|
23
|
+
this.reflect("labelled", value !== "");
|
|
24
|
+
setOrRemove(this._refs.divider, "aria-label", value);
|
|
25
|
+
}, { attribute: "label" });
|
|
26
|
+
vertical = this.useChange(false, (value) => {
|
|
27
|
+
this.reflect("vertical", value);
|
|
28
|
+
this._refs.divider.setAttribute("aria-orientation", value ? "vertical" : "horizontal");
|
|
29
|
+
}, { attribute: "vertical" });
|
|
30
|
+
/** Where the label sits along the line. */
|
|
31
|
+
align = this.useChange("center", (value) => this.reflect("align", value), {
|
|
32
|
+
attribute: "align",
|
|
33
|
+
parse: oneOf(DIVIDER_ALIGNS, "center")
|
|
34
|
+
});
|
|
35
|
+
_refs = this.useRefs((ref) => ({
|
|
36
|
+
divider: ref(".divider"),
|
|
37
|
+
label: ref(".label")
|
|
38
|
+
}));
|
|
39
|
+
templateHtml() {
|
|
40
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
41
|
+
class: "divider",
|
|
42
|
+
role: "separator",
|
|
43
|
+
attrs: { part: "base" },
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ jsx("span", { class: "line before" }),
|
|
46
|
+
/* @__PURE__ */ jsx("span", {
|
|
47
|
+
class: "label",
|
|
48
|
+
hidden: true
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ jsx("span", { class: "line after" })
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
templateCss() {
|
|
55
|
+
return css`${BASE_STYLES}${jl_divider_default}`;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
JlDivider.register();
|
|
59
|
+
export { DIVIDER_ALIGNS, JlDivider };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
/**
|
|
3
|
+
* A lucide icon by name: `<jl-icon name="search">`. Decorative unless it has a `label`, which screen readers
|
|
4
|
+
* read instead. More icons: `registerIcons({ rocket: Rocket })`.
|
|
5
|
+
*/
|
|
6
|
+
export declare class JlIcon extends JlElement {
|
|
7
|
+
static readonly selector = "jl-icon";
|
|
8
|
+
readonly name: Readonly<Readonly<{
|
|
9
|
+
get(): string;
|
|
10
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
11
|
+
}>>;
|
|
12
|
+
readonly size: Readonly<Readonly<{
|
|
13
|
+
get(): number;
|
|
14
|
+
set(setter: number | ((prevState: number) => number)): void;
|
|
15
|
+
}>>;
|
|
16
|
+
readonly label: Readonly<Readonly<{
|
|
17
|
+
get(): string;
|
|
18
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
19
|
+
}>>;
|
|
20
|
+
private readonly _refs;
|
|
21
|
+
templateHtml(): Node;
|
|
22
|
+
templateCss(): string;
|
|
23
|
+
private draw;
|
|
24
|
+
private setAccessibleName;
|
|
25
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
|
+
import { JlElement } from "../base/jl-element.js";
|
|
3
|
+
import { iconElement } from "../lib/icons.js";
|
|
4
|
+
import jl_icon_default from "./jl-icon.css_raw.js";
|
|
5
|
+
import { css } from "@jadis/core";
|
|
6
|
+
import { jsx } from "@jadis/core/jsx-runtime";
|
|
7
|
+
// src/atoms/jl-icon.tsx
|
|
8
|
+
var DEFAULT_SIZE = 16;
|
|
9
|
+
/**
|
|
10
|
+
* A lucide icon by name: `<jl-icon name="search">`. Decorative unless it has a `label`, which screen readers
|
|
11
|
+
* read instead. More icons: `registerIcons({ rocket: Rocket })`.
|
|
12
|
+
*/
|
|
13
|
+
var JlIcon = class extends JlElement {
|
|
14
|
+
static selector = "jl-icon";
|
|
15
|
+
name = this.useChange("", () => this.draw(), { attribute: "name" });
|
|
16
|
+
size = this.useChange(DEFAULT_SIZE, () => this.draw(), { attribute: "size" });
|
|
17
|
+
label = this.useChange("", (value) => this.setAccessibleName(value), { attribute: "label" });
|
|
18
|
+
_refs = this.useRefs((ref) => ({ icon: ref(".icon") }));
|
|
19
|
+
templateHtml() {
|
|
20
|
+
return /* @__PURE__ */ jsx("span", { class: "icon" });
|
|
21
|
+
}
|
|
22
|
+
templateCss() {
|
|
23
|
+
return css`${BASE_STYLES}${jl_icon_default}`;
|
|
24
|
+
}
|
|
25
|
+
draw() {
|
|
26
|
+
const name = this.name.get();
|
|
27
|
+
this._refs.icon.replaceChildren(...name === "" ? [] : [iconElement(name, this.size.get())]);
|
|
28
|
+
}
|
|
29
|
+
setAccessibleName(label) {
|
|
30
|
+
const icon = this._refs.icon;
|
|
31
|
+
if (label === "") {
|
|
32
|
+
icon.removeAttribute("role");
|
|
33
|
+
icon.removeAttribute("aria-label");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
icon.setAttribute("role", "img");
|
|
37
|
+
icon.setAttribute("aria-label", label);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
JlIcon.register();
|
|
41
|
+
export { JlIcon };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/atoms/jl-input.css?raw
|
|
2
|
+
var jl_input_default = ":host {\n display: block;\n}\n\n:host([readonly]) .control {\n background: var(--jl-surface-2);\n}\n\n::slotted([slot=\"start\"]),\n::slotted([slot=\"end\"]) {\n flex: none;\n color: var(--jl-muted);\n font-size: var(--jl-font-sm);\n}\n\n/* The browser's own clear button and spinners: the field draws its own actions. */\n.native::-webkit-search-cancel-button,\n.native::-webkit-inner-spin-button {\n appearance: none;\n}\n\n.native[type=\"date\"],\n.native[type=\"time\"],\n.native[type=\"datetime-local\"],\n.native[type=\"month\"],\n.native[type=\"week\"] {\n font-family: var(--jl-font-mono);\n font-size: var(--jl-font-sm);\n}\n";
|
|
3
|
+
export { jl_input_default as default };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { JlFormControl } from '../base/jl-form-control';
|
|
2
|
+
import type { InputType } from '../types/jl-input.types';
|
|
3
|
+
import type { ControlSize } from '../types/options.types';
|
|
4
|
+
export declare const INPUT_TYPES: readonly InputType[];
|
|
5
|
+
/**
|
|
6
|
+
* A single-line text field that takes part in forms. `value` is the text; `input` fires as people type and
|
|
7
|
+
* `change` when they commit. Slots `start` and `end` hold adornments such as a unit or a prefix.
|
|
8
|
+
*/
|
|
9
|
+
export declare class JlInput extends JlFormControl {
|
|
10
|
+
static readonly selector = "jl-input";
|
|
11
|
+
readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
|
|
12
|
+
input: string;
|
|
13
|
+
change: string;
|
|
14
|
+
}>>;
|
|
15
|
+
readonly value: Readonly<Readonly<{
|
|
16
|
+
get(): string;
|
|
17
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
18
|
+
}>>;
|
|
19
|
+
readonly type: Readonly<Readonly<{
|
|
20
|
+
get(): InputType;
|
|
21
|
+
set(setter: ((prevState: InputType) => InputType) | InputType): void;
|
|
22
|
+
}>>;
|
|
23
|
+
readonly placeholder: Readonly<Readonly<{
|
|
24
|
+
get(): string;
|
|
25
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
26
|
+
}>>;
|
|
27
|
+
/** The field's name for screen readers, when no visible label names it. */
|
|
28
|
+
readonly label: Readonly<Readonly<{
|
|
29
|
+
get(): string;
|
|
30
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
31
|
+
}>>;
|
|
32
|
+
readonly autocomplete: Readonly<Readonly<{
|
|
33
|
+
get(): string;
|
|
34
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
35
|
+
}>>;
|
|
36
|
+
readonly min: Readonly<Readonly<{
|
|
37
|
+
get(): string;
|
|
38
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
39
|
+
}>>;
|
|
40
|
+
readonly max: Readonly<Readonly<{
|
|
41
|
+
get(): string;
|
|
42
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
43
|
+
}>>;
|
|
44
|
+
readonly step: Readonly<Readonly<{
|
|
45
|
+
get(): string;
|
|
46
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
47
|
+
}>>;
|
|
48
|
+
readonly minlength: Readonly<Readonly<{
|
|
49
|
+
get(): string;
|
|
50
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
51
|
+
}>>;
|
|
52
|
+
readonly maxlength: Readonly<Readonly<{
|
|
53
|
+
get(): string;
|
|
54
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
55
|
+
}>>;
|
|
56
|
+
readonly pattern: Readonly<Readonly<{
|
|
57
|
+
get(): string;
|
|
58
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
59
|
+
}>>;
|
|
60
|
+
readonly required: Readonly<Readonly<{
|
|
61
|
+
get(): boolean;
|
|
62
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
63
|
+
}>>;
|
|
64
|
+
readonly readonly: Readonly<Readonly<{
|
|
65
|
+
get(): boolean;
|
|
66
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
67
|
+
}>>;
|
|
68
|
+
readonly disabled: Readonly<Readonly<{
|
|
69
|
+
get(): boolean;
|
|
70
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
71
|
+
}>>;
|
|
72
|
+
/** Draws the field in the danger colour, for an error the page found itself. */
|
|
73
|
+
readonly invalid: Readonly<Readonly<{
|
|
74
|
+
get(): boolean;
|
|
75
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
76
|
+
}>>;
|
|
77
|
+
readonly size: Readonly<Readonly<{
|
|
78
|
+
get(): ControlSize;
|
|
79
|
+
set(setter: ((prevState: ControlSize) => ControlSize) | ControlSize): void;
|
|
80
|
+
}>>;
|
|
81
|
+
/** An icon at the start of the field. */
|
|
82
|
+
readonly icon: Readonly<Readonly<{
|
|
83
|
+
get(): string;
|
|
84
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
85
|
+
}>>;
|
|
86
|
+
/** Shows a button that empties the field while it holds text. */
|
|
87
|
+
readonly clearable: Readonly<Readonly<{
|
|
88
|
+
get(): boolean;
|
|
89
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
90
|
+
}>>;
|
|
91
|
+
private readonly _form;
|
|
92
|
+
private readonly _refs;
|
|
93
|
+
focus(options?: FocusOptions): void;
|
|
94
|
+
/** Selects the whole text, ready to be replaced. */
|
|
95
|
+
select(): void;
|
|
96
|
+
templateHtml(): Node;
|
|
97
|
+
templateCss(): string;
|
|
98
|
+
onConnect(): void;
|
|
99
|
+
protected resetValue(): void;
|
|
100
|
+
/** The browser calls it for a disabled fieldset and for the element's own disabled attribute, even before render. */
|
|
101
|
+
protected setDisabledByForm(disabled: boolean): void;
|
|
102
|
+
private clearValue;
|
|
103
|
+
private toggleReveal;
|
|
104
|
+
private renderValue;
|
|
105
|
+
private renderType;
|
|
106
|
+
private renderDisabled;
|
|
107
|
+
/** The native field is disabled by the element's own flag or by a disabled fieldset around it. */
|
|
108
|
+
private syncNativeDisabled;
|
|
109
|
+
private renderActions;
|
|
110
|
+
private setNative;
|
|
111
|
+
private setFlag;
|
|
112
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { BASE_STYLES, CONTROL_STYLES } from "../styles/shared.js";
|
|
2
|
+
import { JlFormControl } from "../base/jl-form-control.js";
|
|
3
|
+
import { oneOf } from "../lib/attributes.js";
|
|
4
|
+
import { registerIcons } from "../lib/icons.js";
|
|
5
|
+
import { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
7
|
+
import { JlIcon } from "./jl-icon.js";
|
|
8
|
+
import jl_input_default from "./jl-input.css_raw.js";
|
|
9
|
+
import { css } from "@jadis/core";
|
|
10
|
+
import { Eye, EyeOff, X } from "lucide";
|
|
11
|
+
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
12
|
+
// src/atoms/jl-input.tsx
|
|
13
|
+
registerIcons({
|
|
14
|
+
eye: Eye,
|
|
15
|
+
"eye-off": EyeOff,
|
|
16
|
+
x: X
|
|
17
|
+
});
|
|
18
|
+
var INPUT_TYPES = [
|
|
19
|
+
"text",
|
|
20
|
+
"email",
|
|
21
|
+
"password",
|
|
22
|
+
"number",
|
|
23
|
+
"search",
|
|
24
|
+
"tel",
|
|
25
|
+
"url",
|
|
26
|
+
"date",
|
|
27
|
+
"time",
|
|
28
|
+
"datetime-local",
|
|
29
|
+
"month",
|
|
30
|
+
"week"
|
|
31
|
+
];
|
|
32
|
+
var PASSWORD = "password";
|
|
33
|
+
var REVEALED = "text";
|
|
34
|
+
var ICON_SIZE = 16;
|
|
35
|
+
var ACTION_ICON_SIZE = 14;
|
|
36
|
+
/**
|
|
37
|
+
* A single-line text field that takes part in forms. `value` is the text; `input` fires as people type and
|
|
38
|
+
* `change` when they commit. Slots `start` and `end` hold adornments such as a unit or a prefix.
|
|
39
|
+
*/
|
|
40
|
+
var JlInput = class extends JlFormControl {
|
|
41
|
+
static selector = "jl-input";
|
|
42
|
+
events = this.useEvents();
|
|
43
|
+
value = this.useChange("", (value) => this.renderValue(value), { attribute: "value" });
|
|
44
|
+
type = this.useChange("text", (value) => this.renderType(value), {
|
|
45
|
+
attribute: "type",
|
|
46
|
+
parse: oneOf(INPUT_TYPES, "text")
|
|
47
|
+
});
|
|
48
|
+
placeholder = this.useChange("", (value) => this.setNative("placeholder", value), { attribute: "placeholder" });
|
|
49
|
+
/** The field's name for screen readers, when no visible label names it. */
|
|
50
|
+
label = this.useChange("", (value) => this.setNative("aria-label", value), { attribute: "label" });
|
|
51
|
+
autocomplete = this.useChange("", (value) => this.setNative("autocomplete", value), { attribute: "autocomplete" });
|
|
52
|
+
min = this.useChange("", (value) => this.setNative("min", value), { attribute: "min" });
|
|
53
|
+
max = this.useChange("", (value) => this.setNative("max", value), { attribute: "max" });
|
|
54
|
+
step = this.useChange("", (value) => this.setNative("step", value), { attribute: "step" });
|
|
55
|
+
minlength = this.useChange("", (value) => this.setNative("minlength", value), { attribute: "minlength" });
|
|
56
|
+
maxlength = this.useChange("", (value) => this.setNative("maxlength", value), { attribute: "maxlength" });
|
|
57
|
+
pattern = this.useChange("", (value) => this.setNative("pattern", value), { attribute: "pattern" });
|
|
58
|
+
required = this.useChange(false, (value) => this.setFlag("required", value), { attribute: "required" });
|
|
59
|
+
readonly = this.useChange(false, (value) => this.setFlag("readonly", value), { attribute: "readonly" });
|
|
60
|
+
disabled = this.useChange(false, (value) => this.renderDisabled(value), { attribute: "disabled" });
|
|
61
|
+
/** Draws the field in the danger colour, for an error the page found itself. */
|
|
62
|
+
invalid = this.useChange(false, (value) => {
|
|
63
|
+
this.reflect("invalid", value);
|
|
64
|
+
this._refs.native.toggleAttribute("aria-invalid", value);
|
|
65
|
+
}, { attribute: "invalid" });
|
|
66
|
+
size = this.useChange("md", (value) => this.reflect("size", value), {
|
|
67
|
+
attribute: "size",
|
|
68
|
+
parse: oneOf(CONTROL_SIZES, "md")
|
|
69
|
+
});
|
|
70
|
+
/** An icon at the start of the field. */
|
|
71
|
+
icon = this.useChange("", (name) => {
|
|
72
|
+
this._refs.icon.name.set(name);
|
|
73
|
+
this._refs.icon.hidden = name === "";
|
|
74
|
+
}, { attribute: "icon" });
|
|
75
|
+
/** Shows a button that empties the field while it holds text. */
|
|
76
|
+
clearable = this.useChange(false, () => this.renderActions(), { attribute: "clearable" });
|
|
77
|
+
_form = { disabled: false };
|
|
78
|
+
_refs = this.useRefs((ref) => ({
|
|
79
|
+
clear: ref(".clear"),
|
|
80
|
+
icon: ref(".icon"),
|
|
81
|
+
native: ref("input"),
|
|
82
|
+
reveal: ref(".reveal"),
|
|
83
|
+
revealIcon: ref(".reveal jl-icon")
|
|
84
|
+
}));
|
|
85
|
+
focus(options) {
|
|
86
|
+
this._refs.native.focus(options);
|
|
87
|
+
}
|
|
88
|
+
/** Selects the whole text, ready to be replaced. */
|
|
89
|
+
select() {
|
|
90
|
+
this._refs.native.select();
|
|
91
|
+
}
|
|
92
|
+
templateHtml() {
|
|
93
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
94
|
+
class: "control",
|
|
95
|
+
attrs: { part: "base" },
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ jsx(JlIcon, {
|
|
98
|
+
class: "adornment icon",
|
|
99
|
+
size: ICON_SIZE,
|
|
100
|
+
hidden: true
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ jsx("slot", { name: "start" }),
|
|
103
|
+
/* @__PURE__ */ jsx("input", { class: "native" }),
|
|
104
|
+
/* @__PURE__ */ jsx("button", {
|
|
105
|
+
class: "action clear",
|
|
106
|
+
type: "button",
|
|
107
|
+
"aria-label": "Clear",
|
|
108
|
+
tabIndex: -1,
|
|
109
|
+
hidden: true,
|
|
110
|
+
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
111
|
+
name: "x",
|
|
112
|
+
size: ACTION_ICON_SIZE
|
|
113
|
+
})
|
|
114
|
+
}),
|
|
115
|
+
/* @__PURE__ */ jsx("button", {
|
|
116
|
+
class: "action reveal",
|
|
117
|
+
type: "button",
|
|
118
|
+
"aria-label": "Show the password",
|
|
119
|
+
hidden: true,
|
|
120
|
+
children: /* @__PURE__ */ jsx(JlIcon, {
|
|
121
|
+
name: "eye",
|
|
122
|
+
size: ICON_SIZE
|
|
123
|
+
})
|
|
124
|
+
}),
|
|
125
|
+
/* @__PURE__ */ jsx("slot", { name: "end" })
|
|
126
|
+
]
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
templateCss() {
|
|
130
|
+
return css`${BASE_STYLES}${CONTROL_STYLES}${jl_input_default}`;
|
|
131
|
+
}
|
|
132
|
+
onConnect() {
|
|
133
|
+
const native = this._refs.native;
|
|
134
|
+
this.on(native, "input", (event) => {
|
|
135
|
+
event.stopPropagation();
|
|
136
|
+
this.value.set(native.value);
|
|
137
|
+
this.events.emit("input", native.value);
|
|
138
|
+
});
|
|
139
|
+
this.on(native, "change", () => this.events.emit("change", native.value));
|
|
140
|
+
this.on(this._refs.clear, "click", () => this.clearValue());
|
|
141
|
+
this.on(this._refs.reveal, "click", () => this.toggleReveal());
|
|
142
|
+
}
|
|
143
|
+
resetValue() {
|
|
144
|
+
this.value.set(this.getAttribute("value") ?? "");
|
|
145
|
+
}
|
|
146
|
+
/** The browser calls it for a disabled fieldset and for the element's own disabled attribute, even before render. */
|
|
147
|
+
setDisabledByForm(disabled) {
|
|
148
|
+
this._form.disabled = disabled;
|
|
149
|
+
this.whenRendered(() => this.syncNativeDisabled());
|
|
150
|
+
}
|
|
151
|
+
clearValue() {
|
|
152
|
+
this.value.set("");
|
|
153
|
+
this.events.emit("input", "");
|
|
154
|
+
this.events.emit("change", "");
|
|
155
|
+
this.focus();
|
|
156
|
+
}
|
|
157
|
+
toggleReveal() {
|
|
158
|
+
const native = this._refs.native;
|
|
159
|
+
const revealed = native.type === PASSWORD;
|
|
160
|
+
native.type = revealed ? REVEALED : PASSWORD;
|
|
161
|
+
this._refs.revealIcon.name.set(revealed ? "eye-off" : "eye");
|
|
162
|
+
this._refs.reveal.setAttribute("aria-label", revealed ? "Hide the password" : "Show the password");
|
|
163
|
+
}
|
|
164
|
+
renderValue(value) {
|
|
165
|
+
const native = this._refs.native;
|
|
166
|
+
if (native.value !== value) native.value = value;
|
|
167
|
+
this.internals.setFormValue(value);
|
|
168
|
+
this.mirrorValidity(native);
|
|
169
|
+
this.renderActions();
|
|
170
|
+
}
|
|
171
|
+
renderType(type) {
|
|
172
|
+
this._refs.native.type = type;
|
|
173
|
+
this.renderActions();
|
|
174
|
+
this.mirrorValidity(this._refs.native);
|
|
175
|
+
}
|
|
176
|
+
renderDisabled(disabled) {
|
|
177
|
+
this.reflect("disabled", disabled);
|
|
178
|
+
this.syncNativeDisabled();
|
|
179
|
+
}
|
|
180
|
+
/** The native field is disabled by the element's own flag or by a disabled fieldset around it. */
|
|
181
|
+
syncNativeDisabled() {
|
|
182
|
+
this._refs.native.disabled = this.disabled.get() || this._form.disabled;
|
|
183
|
+
this.renderActions();
|
|
184
|
+
}
|
|
185
|
+
renderActions() {
|
|
186
|
+
const editable = !this.disabled.get() && !this.readonly.get();
|
|
187
|
+
this._refs.clear.hidden = !(this.clearable.get() && editable && this.value.get() !== "");
|
|
188
|
+
this._refs.reveal.hidden = this.type.get() !== PASSWORD;
|
|
189
|
+
}
|
|
190
|
+
setNative(name, value) {
|
|
191
|
+
setOrRemove(this._refs.native, name, value);
|
|
192
|
+
this.mirrorValidity(this._refs.native);
|
|
193
|
+
}
|
|
194
|
+
setFlag(name, value) {
|
|
195
|
+
this._refs.native.toggleAttribute(name, value);
|
|
196
|
+
this.reflect(name, value);
|
|
197
|
+
this.renderActions();
|
|
198
|
+
this.mirrorValidity(this._refs.native);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
JlInput.register();
|
|
202
|
+
export { INPUT_TYPES, JlInput };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/atoms/jl-kbd.css?raw
|
|
2
|
+
var jl_kbd_default = ":host {\n display: inline-flex;\n vertical-align: middle;\n}\n\n.keys,\n.caps {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n}\n\n.key {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n border: 1px solid var(--jl-line-strong);\n border-bottom-width: 2px;\n border-radius: var(--jl-radius-xs);\n background: var(--jl-surface-2);\n color: var(--jl-text-2);\n font-family: var(--jl-font-sans);\n font-size: 11px;\n font-weight: 600;\n line-height: 1;\n white-space: nowrap;\n}\n";
|
|
3
|
+
export { jl_kbd_default as default };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
/**
|
|
3
|
+
* A keyboard shortcut, one keycap per key: `keys="mod+shift+k"` draws ⌘ ⇧ K on a Mac and Ctrl Shift K elsewhere.
|
|
4
|
+
* Without `keys`, the element's text is one keycap: `<jl-kbd>Esc</jl-kbd>`.
|
|
5
|
+
*/
|
|
6
|
+
export declare class JlKbd extends JlElement {
|
|
7
|
+
static readonly selector = "jl-kbd";
|
|
8
|
+
/** Keys joined by "+": modifiers (mod, ctrl, alt, shift), named keys (enter, esc, up…) and characters. */
|
|
9
|
+
readonly keys: Readonly<Readonly<{
|
|
10
|
+
get(): string;
|
|
11
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
12
|
+
}>>;
|
|
13
|
+
private readonly _refs;
|
|
14
|
+
templateHtml(): Node;
|
|
15
|
+
templateCss(): string;
|
|
16
|
+
private render;
|
|
17
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
|
+
import { JlElement } from "../base/jl-element.js";
|
|
3
|
+
import { keycapsOf, spokenKeys } from "../lib/keycaps.js";
|
|
4
|
+
import jl_kbd_default from "./jl-kbd.css_raw.js";
|
|
5
|
+
import { css } from "@jadis/core";
|
|
6
|
+
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
7
|
+
// src/atoms/jl-kbd.tsx
|
|
8
|
+
var APPLE_PLATFORM = /mac|iphone|ipad|ipod/i;
|
|
9
|
+
/** Whether this browser runs on an Apple system, where shortcuts use ⌘ rather than Ctrl. */
|
|
10
|
+
function currentPlatform() {
|
|
11
|
+
if (typeof navigator === "undefined") return "other";
|
|
12
|
+
const browser = navigator;
|
|
13
|
+
const platform = browser.userAgentData?.platform ?? browser.platform ?? "";
|
|
14
|
+
return APPLE_PLATFORM.test(platform) ? "apple" : "other";
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A keyboard shortcut, one keycap per key: `keys="mod+shift+k"` draws ⌘ ⇧ K on a Mac and Ctrl Shift K elsewhere.
|
|
18
|
+
* Without `keys`, the element's text is one keycap: `<jl-kbd>Esc</jl-kbd>`.
|
|
19
|
+
*/
|
|
20
|
+
var JlKbd = class extends JlElement {
|
|
21
|
+
static selector = "jl-kbd";
|
|
22
|
+
/** Keys joined by "+": modifiers (mod, ctrl, alt, shift), named keys (enter, esc, up…) and characters. */
|
|
23
|
+
keys = this.useChange("", () => this.render(), { attribute: "keys" });
|
|
24
|
+
_refs = this.useRefs((ref) => ({
|
|
25
|
+
caps: ref(".caps"),
|
|
26
|
+
own: ref(".own"),
|
|
27
|
+
spoken: ref(".spoken")
|
|
28
|
+
}));
|
|
29
|
+
templateHtml() {
|
|
30
|
+
return /* @__PURE__ */ jsxs("kbd", {
|
|
31
|
+
class: "keys",
|
|
32
|
+
attrs: { part: "base" },
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ jsx("span", {
|
|
35
|
+
class: "caps",
|
|
36
|
+
"aria-hidden": "true"
|
|
37
|
+
}),
|
|
38
|
+
/* @__PURE__ */ jsx("span", { class: "spoken sr-only" }),
|
|
39
|
+
/* @__PURE__ */ jsx("kbd", {
|
|
40
|
+
class: "key own",
|
|
41
|
+
children: /* @__PURE__ */ jsx("slot", {})
|
|
42
|
+
})
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
templateCss() {
|
|
47
|
+
return css`${BASE_STYLES}${jl_kbd_default}`;
|
|
48
|
+
}
|
|
49
|
+
render() {
|
|
50
|
+
const keycaps = keycapsOf(this.keys.get(), currentPlatform());
|
|
51
|
+
const own = keycaps.length === 0;
|
|
52
|
+
this._refs.caps.replaceChildren(...keycaps.map((keycap) => /* @__PURE__ */ jsx("kbd", {
|
|
53
|
+
class: "key",
|
|
54
|
+
children: keycap.label
|
|
55
|
+
})));
|
|
56
|
+
this._refs.spoken.textContent = spokenKeys(keycaps);
|
|
57
|
+
this._refs.own.hidden = !own;
|
|
58
|
+
this._refs.caps.hidden = own;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
JlKbd.register();
|
|
62
|
+
export { JlKbd };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/atoms/jl-link.css?raw
|
|
2
|
+
var jl_link_default = ":host {\n display: inline;\n --color: var(--jl-accent);\n --hover: var(--jl-accent-strong);\n --underline: color-mix(in srgb, var(--jl-accent) 40%, transparent);\n}\n\n:host([variant=\"muted\"]) {\n --color: var(--jl-muted);\n --hover: var(--jl-text);\n --underline: transparent;\n}\n\n:host([variant=\"quiet\"]) {\n --underline: transparent;\n}\n\na {\n border-radius: 3px;\n color: var(--color);\n font-weight: 600;\n text-decoration: underline;\n text-decoration-color: var(--underline);\n text-decoration-thickness: 1px;\n text-underline-offset: 0.2em;\n cursor: pointer;\n transition:\n color var(--jl-fast) var(--jl-ease),\n text-decoration-color var(--jl-fast) var(--jl-ease);\n}\n\na:hover {\n color: var(--hover);\n text-decoration-color: currentColor;\n}\n\na:not([href]) {\n cursor: default;\n}\n\njl-icon {\n margin-left: 0.2em;\n vertical-align: -0.1em;\n}\n";
|
|
3
|
+
export { jl_link_default as default };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
import type { LinkVariant } from '../types/jl-link.types';
|
|
3
|
+
export declare const LINK_VARIANTS: readonly LinkVariant[];
|
|
4
|
+
/**
|
|
5
|
+
* A link in text or in a list: the browser's own `<a>`, styled. `external` opens it in a new tab, safely, with an
|
|
6
|
+
* icon that says so. Its text is the `label` or the slotted content.
|
|
7
|
+
*/
|
|
8
|
+
export declare class JlLink extends JlElement {
|
|
9
|
+
static readonly selector = "jl-link";
|
|
10
|
+
readonly href: Readonly<Readonly<{
|
|
11
|
+
get(): string;
|
|
12
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
13
|
+
}>>;
|
|
14
|
+
readonly label: Readonly<Readonly<{
|
|
15
|
+
get(): string;
|
|
16
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
17
|
+
}>>;
|
|
18
|
+
/** Where it opens, as an `<a>`'s `target`: `_blank` for a new tab. */
|
|
19
|
+
readonly target: Readonly<Readonly<{
|
|
20
|
+
get(): string;
|
|
21
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
22
|
+
}>>;
|
|
23
|
+
/** Leads away from the app: opens in a new tab, with an icon and without sharing the page. */
|
|
24
|
+
readonly external: Readonly<Readonly<{
|
|
25
|
+
get(): boolean;
|
|
26
|
+
set(setter: boolean | ((prevState: boolean) => boolean)): void;
|
|
27
|
+
}>>;
|
|
28
|
+
readonly variant: Readonly<Readonly<{
|
|
29
|
+
get(): LinkVariant;
|
|
30
|
+
set(setter: ((prevState: LinkVariant) => LinkVariant) | LinkVariant): void;
|
|
31
|
+
}>>;
|
|
32
|
+
private readonly _refs;
|
|
33
|
+
focus(options?: FocusOptions): void;
|
|
34
|
+
templateHtml(): Node;
|
|
35
|
+
templateCss(): string;
|
|
36
|
+
private renderTarget;
|
|
37
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
|
+
import { JlElement } from "../base/jl-element.js";
|
|
3
|
+
import { oneOf } from "../lib/attributes.js";
|
|
4
|
+
import { registerIcons } from "../lib/icons.js";
|
|
5
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
6
|
+
import { JlIcon } from "./jl-icon.js";
|
|
7
|
+
import jl_link_default from "./jl-link.css_raw.js";
|
|
8
|
+
import { css } from "@jadis/core";
|
|
9
|
+
import { ExternalLink } from "lucide";
|
|
10
|
+
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
11
|
+
// src/atoms/jl-link.tsx
|
|
12
|
+
registerIcons({ "external-link": ExternalLink });
|
|
13
|
+
var LINK_VARIANTS = [
|
|
14
|
+
"default",
|
|
15
|
+
"quiet",
|
|
16
|
+
"muted"
|
|
17
|
+
];
|
|
18
|
+
var NEW_TAB = "_blank";
|
|
19
|
+
var SAFE_REL = "noopener noreferrer";
|
|
20
|
+
var ICON_SIZE = 13;
|
|
21
|
+
/**
|
|
22
|
+
* A link in text or in a list: the browser's own `<a>`, styled. `external` opens it in a new tab, safely, with an
|
|
23
|
+
* icon that says so. Its text is the `label` or the slotted content.
|
|
24
|
+
*/
|
|
25
|
+
var JlLink = class extends JlElement {
|
|
26
|
+
static selector = "jl-link";
|
|
27
|
+
href = this.useChange("", (value) => setOrRemove(this._refs.anchor, "href", value), { attribute: "href" });
|
|
28
|
+
label = this.useChange("", (value) => {
|
|
29
|
+
this._refs.label.textContent = value;
|
|
30
|
+
this._refs.label.hidden = value === "";
|
|
31
|
+
}, { attribute: "label" });
|
|
32
|
+
/** Where it opens, as an `<a>`'s `target`: `_blank` for a new tab. */
|
|
33
|
+
target = this.useChange("", () => this.renderTarget(), { attribute: "target" });
|
|
34
|
+
/** Leads away from the app: opens in a new tab, with an icon and without sharing the page. */
|
|
35
|
+
external = this.useChange(false, () => this.renderTarget(), { attribute: "external" });
|
|
36
|
+
variant = this.useChange("default", (value) => this.reflect("variant", value), {
|
|
37
|
+
attribute: "variant",
|
|
38
|
+
parse: oneOf(LINK_VARIANTS, "default")
|
|
39
|
+
});
|
|
40
|
+
_refs = this.useRefs((ref) => ({
|
|
41
|
+
anchor: ref("a"),
|
|
42
|
+
icon: ref("jl-icon"),
|
|
43
|
+
label: ref(".label"),
|
|
44
|
+
newTab: ref(".new-tab")
|
|
45
|
+
}));
|
|
46
|
+
focus(options) {
|
|
47
|
+
this._refs.anchor.focus(options);
|
|
48
|
+
}
|
|
49
|
+
templateHtml() {
|
|
50
|
+
return /* @__PURE__ */ jsxs("a", {
|
|
51
|
+
attrs: { part: "base" },
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsx("span", {
|
|
54
|
+
class: "label",
|
|
55
|
+
hidden: true
|
|
56
|
+
}),
|
|
57
|
+
/* @__PURE__ */ jsx("slot", {}),
|
|
58
|
+
/* @__PURE__ */ jsx(JlIcon, {
|
|
59
|
+
name: "external-link",
|
|
60
|
+
size: ICON_SIZE,
|
|
61
|
+
hidden: true
|
|
62
|
+
}),
|
|
63
|
+
/* @__PURE__ */ jsx("span", {
|
|
64
|
+
class: "new-tab sr-only",
|
|
65
|
+
hidden: true,
|
|
66
|
+
children: "(opens in a new tab)"
|
|
67
|
+
})
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
templateCss() {
|
|
72
|
+
return css`${BASE_STYLES}${jl_link_default}`;
|
|
73
|
+
}
|
|
74
|
+
renderTarget() {
|
|
75
|
+
const anchor = this._refs.anchor;
|
|
76
|
+
const external = this.external.get();
|
|
77
|
+
const target = this.target.get() || (external ? NEW_TAB : "");
|
|
78
|
+
const newTab = target === NEW_TAB;
|
|
79
|
+
setOrRemove(anchor, "target", target);
|
|
80
|
+
setOrRemove(anchor, "rel", external || newTab ? SAFE_REL : "");
|
|
81
|
+
this._refs.icon.hidden = !external;
|
|
82
|
+
this._refs.newTab.hidden = !newTab;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
JlLink.register();
|
|
86
|
+
export { JlLink, LINK_VARIANTS };
|