@syware/jlib 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/all.js +5 -3
- package/dist/atoms/jl-app-icon.css_raw.js +3 -0
- package/dist/atoms/jl-app-icon.d.ts +29 -0
- package/dist/atoms/jl-app-icon.js +64 -0
- package/dist/atoms/jl-avatar.js +1 -1
- package/dist/atoms/jl-badge.js +8 -1
- package/dist/atoms/jl-button.js +1 -1
- package/dist/atoms/jl-input.js +1 -1
- package/dist/atoms/jl-link.js +1 -1
- package/dist/atoms/jl-select.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -2
- package/dist/lib/text.d.ts +10 -0
- package/dist/lib/text.js +13 -1
- package/dist/lib/time.d.ts +5 -3
- package/dist/lib/time.js +23 -15
- package/dist/lib/trigger.js +1 -1
- package/dist/molecules/jl-account-button.css_raw.js +1 -1
- package/dist/molecules/jl-account-button.d.ts +8 -1
- package/dist/molecules/jl-account-button.js +8 -1
- package/dist/molecules/jl-alert.js +1 -1
- package/dist/molecules/jl-calendar.js +1 -1
- package/dist/molecules/jl-chip-group.js +1 -1
- package/dist/molecules/jl-combobox.js +1 -1
- package/dist/molecules/jl-date-picker.js +1 -1
- package/dist/molecules/jl-empty.js +1 -1
- package/dist/molecules/jl-file-drop.js +1 -1
- package/dist/molecules/jl-list-item.js +1 -1
- package/dist/molecules/jl-load-state.d.ts +4 -1
- package/dist/molecules/jl-load-state.js +14 -5
- package/dist/molecules/jl-menu.js +1 -1
- package/dist/molecules/jl-number-input.js +1 -1
- package/dist/molecules/jl-search-button.js +1 -1
- package/dist/molecules/jl-search.js +1 -1
- package/dist/molecules/jl-segmented.js +1 -1
- package/dist/molecules/jl-tabs.js +1 -1
- package/dist/molecules/jl-tag-input.js +1 -1
- package/dist/molecules/jl-timeline.js +1 -1
- package/dist/molecules/jl-tooltip.d.ts +4 -1
- package/dist/molecules/jl-tooltip.js +27 -15
- package/dist/organisms/jl-command-palette.css_raw.js +1 -1
- package/dist/organisms/jl-command-palette.js +1 -1
- package/dist/organisms/jl-confirm.d.ts +2 -1
- package/dist/organisms/jl-confirm.js +16 -8
- package/dist/organisms/jl-flow.js +1 -1
- package/dist/organisms/jl-side-nav.js +1 -1
- package/dist/organisms/jl-tab-bar.js +1 -1
- package/dist/organisms/jl-table.js +1 -1
- package/dist/organisms/jl-toaster.css_raw.js +1 -1
- package/dist/organisms/jl-tree.js +1 -1
- package/dist/styles/tokens.css_raw.js +1 -1
- package/dist/templates/jl-app-shell.d.ts +6 -1
- package/dist/templates/jl-app-shell.js +27 -2
- package/dist/templates/jl-auth-layout.css_raw.js +3 -0
- package/dist/templates/jl-auth-layout.d.ts +35 -0
- package/dist/templates/jl-auth-layout.js +139 -0
- package/dist/templates/jl-page.css_raw.js +1 -1
- package/dist/templates/jl-split-view.css_raw.js +1 -1
- package/dist/templates/jl-split-view.d.ts +21 -1
- package/dist/templates/jl-split-view.js +33 -1
- package/dist/tokens.css +2 -0
- package/dist/types/jl-split-view.types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -3,8 +3,8 @@ import { JlFormControl } from "../base/jl-form-control.js";
|
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
5
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
7
6
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
7
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
8
8
|
import { clamp, parseNumber, stepValue } from "../lib/numeric.js";
|
|
9
9
|
import jl_number_input_default from "./jl-number-input.css_raw.js";
|
|
10
10
|
import { css } from "@jadis/core";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { registerIcons } from "../lib/icons.js";
|
|
4
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
5
4
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
5
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
6
6
|
import { JlKbd } from "../atoms/jl-kbd.js";
|
|
7
7
|
import { parseShortcut, shortcutAria } from "../lib/key-shortcut.js";
|
|
8
8
|
import jl_search_button_default from "./jl-search-button.css_raw.js";
|
|
@@ -3,8 +3,8 @@ import { JlFormControl } from "../base/jl-form-control.js";
|
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
5
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
6
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
7
6
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
7
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
8
8
|
import { JlSpinner } from "../atoms/jl-spinner.js";
|
|
9
9
|
import { hasCommandModifier, matchesShortcut, parseShortcut, shortcutAria, shortcutLabels } from "../lib/key-shortcut.js";
|
|
10
10
|
import jl_search_default from "./jl-search.css_raw.js";
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlFormControl } from "../base/jl-form-control.js";
|
|
3
3
|
import { jsonOf, oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
5
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
7
7
|
import { firstIndex, lastIndex, stepIndex } from "../lib/roving.js";
|
|
8
8
|
import { moveIndicator } from "../lib/indicator.js";
|
|
9
9
|
import jl_segmented_default from "./jl-segmented.css_raw.js";
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { define } from "../lib/define.js";
|
|
5
|
-
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
7
7
|
import { firstIndex, lastIndex, stepIndex } from "../lib/roving.js";
|
|
8
8
|
import { moveIndicator } from "../lib/indicator.js";
|
|
9
9
|
import { JlTabPanel } from "./jl-tab-panel.js";
|
|
@@ -4,8 +4,8 @@ import { clampedNumber, jsonOf, oneOf } from "../lib/attributes.js";
|
|
|
4
4
|
import { followAnchor } from "../lib/floating.js";
|
|
5
5
|
import { registerIcons } from "../lib/icons.js";
|
|
6
6
|
import { CONTROL_SIZES } from "../lib/options.js";
|
|
7
|
-
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
8
7
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
8
|
+
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
9
9
|
import { keepInView } from "../lib/keep-in-view.js";
|
|
10
10
|
import { filterOptions, matchParts, nextEnabledIndex } from "../lib/option-filter.js";
|
|
11
11
|
import { addTags, hasTag, hasTagSeparator, splitTags } from "../lib/tags.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf } from "../lib/attributes.js";
|
|
4
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
5
4
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
5
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
6
6
|
import jl_timeline_default from "./jl-timeline.css_raw.js";
|
|
7
7
|
import { css } from "@jadis/core";
|
|
8
8
|
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
@@ -41,10 +41,13 @@ export declare class JlTooltip extends JlElement {
|
|
|
41
41
|
private isInteractive;
|
|
42
42
|
private pressStart;
|
|
43
43
|
private pressMove;
|
|
44
|
-
/** The finger lifted
|
|
44
|
+
/** The finger lifted. On a trigger that does nothing else on a tap, a tap (not a scroll) shows or hides the bubble. */
|
|
45
|
+
private pressUp;
|
|
46
|
+
/** The finger is gone: a bubble the long press showed stays a moment, then goes. */
|
|
45
47
|
private pressEnd;
|
|
46
48
|
/** The system's own long press: the bubble shows now, and the menu it would open does not, but over a link. */
|
|
47
49
|
private pressHeld;
|
|
50
|
+
/** The long press shows the bubble, and says whether there is one: without a text, the press stays a press. */
|
|
48
51
|
private openFromPress;
|
|
49
52
|
private swallowLongPress;
|
|
50
53
|
private hideBubble;
|
|
@@ -51,6 +51,7 @@ var JlTooltip = class extends JlElement {
|
|
|
51
51
|
hideTimer: 0,
|
|
52
52
|
press: {
|
|
53
53
|
down: false,
|
|
54
|
+
moved: false,
|
|
54
55
|
opened: false,
|
|
55
56
|
timer: 0,
|
|
56
57
|
x: 0,
|
|
@@ -94,7 +95,7 @@ var JlTooltip = class extends JlElement {
|
|
|
94
95
|
this.hideBubble();
|
|
95
96
|
});
|
|
96
97
|
this.on(this, "pointermove", (event) => this.pressMove(event));
|
|
97
|
-
this.on(this, "pointerup", () => this.
|
|
98
|
+
this.on(this, "pointerup", () => this.pressUp());
|
|
98
99
|
this.on(this, "pointercancel", () => this.pressEnd());
|
|
99
100
|
this.on(this, "contextmenu", (event) => this.pressHeld(event));
|
|
100
101
|
this.addEventListener("click", (event) => this.swallowLongPress(event), {
|
|
@@ -131,26 +132,34 @@ var JlTooltip = class extends JlElement {
|
|
|
131
132
|
pressStart(event) {
|
|
132
133
|
const press = this._state.press;
|
|
133
134
|
window.clearTimeout(press.timer);
|
|
134
|
-
press.opened = false;
|
|
135
|
-
if (!this.isInteractive()) {
|
|
136
|
-
if (this.isOpen()) {
|
|
137
|
-
this.close();
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
this.open();
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
135
|
press.down = true;
|
|
136
|
+
press.moved = false;
|
|
137
|
+
press.opened = false;
|
|
144
138
|
press.x = event.clientX;
|
|
145
139
|
press.y = event.clientY;
|
|
146
|
-
press.timer = window.setTimeout(() => this.openFromPress(), LONG_PRESS_MS);
|
|
140
|
+
if (this.isInteractive()) press.timer = window.setTimeout(() => this.openFromPress(), LONG_PRESS_MS);
|
|
147
141
|
}
|
|
148
142
|
pressMove(event) {
|
|
149
143
|
const press = this._state.press;
|
|
150
144
|
const moved = Math.hypot(event.clientX - press.x, event.clientY - press.y);
|
|
151
|
-
if (press.down && moved > MOVE_TOLERANCE_PX)
|
|
145
|
+
if (press.down && moved > MOVE_TOLERANCE_PX) {
|
|
146
|
+
press.moved = true;
|
|
147
|
+
window.clearTimeout(press.timer);
|
|
148
|
+
}
|
|
152
149
|
}
|
|
153
|
-
/** The finger lifted
|
|
150
|
+
/** The finger lifted. On a trigger that does nothing else on a tap, a tap (not a scroll) shows or hides the bubble. */
|
|
151
|
+
pressUp() {
|
|
152
|
+
const press = this._state.press;
|
|
153
|
+
const tapped = press.down && !press.moved;
|
|
154
|
+
this.pressEnd();
|
|
155
|
+
if (!tapped || this.isInteractive()) return;
|
|
156
|
+
if (this.isOpen()) {
|
|
157
|
+
this.close();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.open();
|
|
161
|
+
}
|
|
162
|
+
/** The finger is gone: a bubble the long press showed stays a moment, then goes. */
|
|
154
163
|
pressEnd() {
|
|
155
164
|
const press = this._state.press;
|
|
156
165
|
window.clearTimeout(press.timer);
|
|
@@ -162,13 +171,15 @@ var JlTooltip = class extends JlElement {
|
|
|
162
171
|
/** The system's own long press: the bubble shows now, and the menu it would open does not, but over a link. */
|
|
163
172
|
pressHeld(event) {
|
|
164
173
|
if (!this._state.press.down || !this.isInteractive()) return;
|
|
165
|
-
this.openFromPress();
|
|
166
|
-
if (!accessibleTarget(this.trigger()).matches("a[href]")) event.preventDefault();
|
|
174
|
+
if (this.openFromPress() && !accessibleTarget(this.trigger()).matches("a[href]")) event.preventDefault();
|
|
167
175
|
}
|
|
176
|
+
/** The long press shows the bubble, and says whether there is one: without a text, the press stays a press. */
|
|
168
177
|
openFromPress() {
|
|
169
178
|
window.clearTimeout(this._state.press.timer);
|
|
179
|
+
if (this.text.get() === "") return false;
|
|
170
180
|
this._state.press.opened = true;
|
|
171
181
|
this.open();
|
|
182
|
+
return true;
|
|
172
183
|
}
|
|
173
184
|
swallowLongPress(event) {
|
|
174
185
|
const press = this._state.press;
|
|
@@ -178,6 +189,7 @@ var JlTooltip = class extends JlElement {
|
|
|
178
189
|
event.stopPropagation();
|
|
179
190
|
}
|
|
180
191
|
hideBubble() {
|
|
192
|
+
window.clearTimeout(this._state.press.timer);
|
|
181
193
|
window.clearTimeout(this._state.showTimer);
|
|
182
194
|
window.clearTimeout(this._state.hideTimer);
|
|
183
195
|
this._state.following.abort();
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/organisms/jl-command-palette.css?raw
|
|
2
|
-
var jl_command_palette_default = ":host {\n display: contents;\n}\n\ndialog {\n flex-direction: column;\n width: min(620px, calc(100vw - 24px));\n max-width: none;\n max-height: min(520px, calc(100dvh - 24vh));\n margin: 12vh auto auto;\n padding: 0;\n overflow: hidden;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius-lg);\n background: var(--jl-surface);\n color: var(--jl-text);\n font-size: var(--jl-font-md);\n box-shadow: var(--jl-shadow-lg);\n}\n\ndialog[open] {\n display: flex;\n animation: drop var(--jl-fast) var(--jl-ease);\n}\n\ndialog::backdrop {\n background: var(--jl-scrim);\n backdrop-filter: blur(2px);\n}\n\n.search {\n display: flex;\n flex: none;\n align-items: center;\n gap: 10px;\n height: 52px;\n padding: 0 14px 0 16px;\n border-bottom: 1px solid var(--jl-line);\n}\n\n.search-icon {\n color: var(--jl-faint);\n}\n\ninput {\n flex: 1;\n min-width: 0;\n height: 100%;\n padding: 0;\n border: none;\n outline: none;\n background: none;\n font-size: 15px;\n}\n\ninput::placeholder {\n color: var(--jl-faint);\n}\n\ninput:focus-visible {\n box-shadow: none;\n}\n\nkbd {\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);\n color: var(--jl-muted);\n font-size: 11px;\n font-weight: 500;\n line-height: 1;\n}\n\n.results {\n flex: 1;\n min-height: 0;\n padding: 6px;\n overflow-y: auto;\n overscroll-behavior: contain;\n scroll-padding: 6px;\n}\n\n[role=\"group\"] + [role=\"group\"] {\n margin-top: 4px;\n padding-top: 4px;\n border-top: 1px solid var(--jl-line-soft);\n}\n\n.group-label {\n padding: 8px 10px 4px;\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n font-weight: 600;\n}\n\n.option {\n display: flex;\n align-items: center;\n gap: 10px;\n min-height: 38px;\n padding: 0 10px;\n border-radius: var(--jl-radius-sm);\n color: var(--jl-text-2);\n cursor: pointer;\n}\n\n.option[aria-selected=\"true\"] {\n background: var(--jl-accent-soft);\n color: var(--jl-text);\n}\n\n.option-icon {\n flex: none;\n width: 16px;\n color: var(--jl-muted);\n}\n\n.option[aria-selected=\"true\"] .option-icon {\n color: var(--jl-accent);\n}\n\n.option-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\nmark {\n background: none;\n color: var(--jl-accent);\n font-weight: 700;\n}\n\n.keys {\n display: inline-flex;\n flex: none;\n gap: 3px;\n}\n\n.empty {\n padding: 36px 16px;\n color: var(--jl-muted);\n text-align: center;\n}\n\nfooter {\n display: flex;\n flex: none;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px 16px;\n padding: 8px 16px;\n border-top: 1px solid var(--jl-line);\n background: var(--jl-surface-2);\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n}\n\n.hint,\n.hotkey-keys {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.hotkey-hint {\n margin-left: auto;\n}\n\n@media (width < 520px) {\n dialog {\n margin-top: 12px;\n max-height: calc(100dvh - 24px);\n }\n\n .hotkey-hint {\n display: none;\n }\n}\n\n@keyframes drop {\n from {\n opacity: 0;\n transform: translateY(-6px) scale(0.98);\n }\n}\n";
|
|
2
|
+
var jl_command_palette_default = ":host {\n display: contents;\n}\n\ndialog {\n flex-direction: column;\n width: min(620px, calc(100vw - 24px));\n max-width: none;\n max-height: min(520px, calc(100dvh - 24vh));\n margin: 12vh auto auto;\n padding: 0;\n overflow: hidden;\n border: 1px solid var(--jl-line);\n border-radius: var(--jl-radius-lg);\n background: var(--jl-surface);\n color: var(--jl-text);\n font-size: var(--jl-font-md);\n box-shadow: var(--jl-shadow-lg);\n}\n\ndialog[open] {\n display: flex;\n animation: drop var(--jl-fast) var(--jl-ease);\n}\n\ndialog::backdrop {\n background: var(--jl-scrim);\n backdrop-filter: blur(2px);\n}\n\n.search {\n display: flex;\n flex: none;\n align-items: center;\n gap: 10px;\n height: 52px;\n padding: 0 14px 0 16px;\n border-bottom: 1px solid var(--jl-line);\n}\n\n.search-icon {\n color: var(--jl-faint);\n}\n\ninput {\n flex: 1;\n min-width: 0;\n height: 100%;\n padding: 0;\n border: none;\n outline: none;\n background: none;\n /* At least the text of fields: 16px on touch screens, where phones zoom into smaller text. */\n font-size: max(15px, var(--jl-control-font));\n}\n\ninput::placeholder {\n color: var(--jl-faint);\n}\n\ninput:focus-visible {\n box-shadow: none;\n}\n\nkbd {\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);\n color: var(--jl-muted);\n font-size: 11px;\n font-weight: 500;\n line-height: 1;\n}\n\n.results {\n flex: 1;\n min-height: 0;\n padding: 6px;\n overflow-y: auto;\n overscroll-behavior: contain;\n scroll-padding: 6px;\n}\n\n[role=\"group\"] + [role=\"group\"] {\n margin-top: 4px;\n padding-top: 4px;\n border-top: 1px solid var(--jl-line-soft);\n}\n\n.group-label {\n padding: 8px 10px 4px;\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n font-weight: 600;\n}\n\n.option {\n display: flex;\n align-items: center;\n gap: 10px;\n min-height: 38px;\n padding: 0 10px;\n border-radius: var(--jl-radius-sm);\n color: var(--jl-text-2);\n cursor: pointer;\n}\n\n.option[aria-selected=\"true\"] {\n background: var(--jl-accent-soft);\n color: var(--jl-text);\n}\n\n.option-icon {\n flex: none;\n width: 16px;\n color: var(--jl-muted);\n}\n\n.option[aria-selected=\"true\"] .option-icon {\n color: var(--jl-accent);\n}\n\n.option-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\nmark {\n background: none;\n color: var(--jl-accent);\n font-weight: 700;\n}\n\n.keys {\n display: inline-flex;\n flex: none;\n gap: 3px;\n}\n\n.empty {\n padding: 36px 16px;\n color: var(--jl-muted);\n text-align: center;\n}\n\nfooter {\n display: flex;\n flex: none;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px 16px;\n padding: 8px 16px;\n border-top: 1px solid var(--jl-line);\n background: var(--jl-surface-2);\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n}\n\n.hint,\n.hotkey-keys {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.hotkey-hint {\n margin-left: auto;\n}\n\n@media (width < 520px) {\n dialog {\n margin-top: 12px;\n max-height: calc(100dvh - 24px);\n }\n\n .hotkey-hint {\n display: none;\n }\n}\n\n@keyframes drop {\n from {\n opacity: 0;\n transform: translateY(-6px) scale(0.98);\n }\n}\n";
|
|
3
3
|
export { jl_command_palette_default as default };
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
7
7
|
import { highlightSegments } from "../lib/fuzzy.js";
|
|
8
8
|
import { hotkeyLabels, isApplePlatform, matchesHotkey, parseHotkey } from "../lib/hotkey.js";
|
|
9
9
|
import { groupMatches, matchCommands } from "../lib/palette.js";
|
|
@@ -57,6 +57,7 @@ export declare function confirmDialog(options: ConfirmOptions): Promise<boolean>
|
|
|
57
57
|
/**
|
|
58
58
|
* Guards a form or an editor against leaving with changes not saved. Closing or reloading the tab asks the
|
|
59
59
|
* browser's own question; the function it returns asks in the page, for the app's router to call before it moves
|
|
60
|
-
* on: `if (!(await canLeave())) return;`. It resolves `true` at once when nothing would be lost
|
|
60
|
+
* on: `if (!(await canLeave())) return;`. It resolves `true` at once when nothing would be lost, or once `signal`
|
|
61
|
+
* ended the guard.
|
|
61
62
|
*/
|
|
62
63
|
export declare function guardLeave(options: LeaveGuardOptions): () => Promise<boolean>;
|
|
@@ -136,18 +136,26 @@ var STAY_LABEL = "Keep editing";
|
|
|
136
136
|
/**
|
|
137
137
|
* Guards a form or an editor against leaving with changes not saved. Closing or reloading the tab asks the
|
|
138
138
|
* browser's own question; the function it returns asks in the page, for the app's router to call before it moves
|
|
139
|
-
* on: `if (!(await canLeave())) return;`. It resolves `true` at once when nothing would be lost
|
|
139
|
+
* on: `if (!(await canLeave())) return;`. It resolves `true` at once when nothing would be lost, or once `signal`
|
|
140
|
+
* ended the guard.
|
|
140
141
|
*/
|
|
141
142
|
function guardLeave(options) {
|
|
142
143
|
window.addEventListener("beforeunload", (event) => {
|
|
143
144
|
if (options.isDirty()) event.preventDefault();
|
|
144
145
|
}, { signal: options.signal });
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
const asking = { pending: null };
|
|
147
|
+
return () => {
|
|
148
|
+
if (options.signal.aborted || !options.isDirty()) return Promise.resolve(true);
|
|
149
|
+
asking.pending ??= confirmDialog({
|
|
150
|
+
cancelLabel: options.stayLabel ?? STAY_LABEL,
|
|
151
|
+
confirmLabel: options.leaveLabel ?? LEAVE_LABEL,
|
|
152
|
+
heading: options.heading ?? LEAVE_HEADING,
|
|
153
|
+
text: options.text ?? LEAVE_TEXT,
|
|
154
|
+
tone: "danger"
|
|
155
|
+
}).finally(() => {
|
|
156
|
+
asking.pending = null;
|
|
157
|
+
});
|
|
158
|
+
return asking.pending;
|
|
159
|
+
};
|
|
152
160
|
}
|
|
153
161
|
export { CONFIRM_TONES, JlConfirm, confirmDialog, guardLeave };
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
-
import { setOrRemove, svgElement } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove, svgElement } from "../lib/dom.js";
|
|
7
7
|
import { FLOW_NODE, FLOW_ZOOM, centeredAt, connect, edgeEnds, edgeMidpoint, edgePath, fitView, isEdgeTaken, isPortFree, layoutFlow, moveNode, nodeAt, nodeHeight, outputAnchor, portX, portsOf, positionAfter, removeEdge, removeNode, revealIn, snap, toWorld, zoomAt } from "../lib/flow.js";
|
|
8
8
|
import jl_flow_default from "./jl-flow.css_raw.js";
|
|
9
9
|
import { css } from "@jadis/core";
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
-
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
7
7
|
import { findItem, firstLeaf, pathInSections } from "../lib/nav-tree.js";
|
|
8
8
|
import jl_side_nav_default from "./jl-side-nav.css_raw.js";
|
|
9
9
|
import { css } from "@jadis/core";
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
7
7
|
import jl_tab_bar_default from "./jl-tab-bar.css_raw.js";
|
|
8
8
|
import { css } from "@jadis/core";
|
|
9
9
|
import { Ellipsis } from "lucide";
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf, oneOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
-
import { setOrRemove } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
7
7
|
import { JlBadge } from "../atoms/jl-badge.js";
|
|
8
8
|
import { columnAlign, columnWidth, formatCell, nextSortDirection, rowKeyOf, selectionState, sortRows, toggleAll, toggleKey } from "../lib/table.js";
|
|
9
9
|
import jl_table_default from "./jl-table.css_raw.js";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/organisms/jl-toaster.css?raw
|
|
2
|
-
var jl_toaster_default = ":host {\n display: contents;\n --edge: 16px;\n --width: 380px;\n}\n\n.region {\n position: fixed;\n inset: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: min(var(--width), calc(100vw - 2 * var(--edge)));\n margin: 0;\n padding: 0;\n overflow: visible;\n border: none;\n background: none;\n color: var(--jl-text);\n /* The empty space between toasts lets clicks through to the page. */\n pointer-events: none;\n}\n\n.region:not(:popover-open) {\n display: none;\n}\n\n::slotted(*) {\n pointer-events: auto;\n}\n\n::slotted([data-stacked]) {\n display: none;\n}\n\n:host([placement=\"bottom-right\"]) .region {\n right: var(--edge);\n bottom: var(--
|
|
2
|
+
var jl_toaster_default = ":host {\n display: contents;\n --edge: 16px;\n --width: 380px;\n}\n\n/* The bottom placements keep above the tab bar of an app shell (--jl-shell-bottom), or --edge-bottom when given. */\n.region {\n --bottom: var(--edge-bottom, calc(var(--edge) + var(--jl-shell-bottom, 0px)));\n}\n\n.region {\n position: fixed;\n inset: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: min(var(--width), calc(100vw - 2 * var(--edge)));\n margin: 0;\n padding: 0;\n overflow: visible;\n border: none;\n background: none;\n color: var(--jl-text);\n /* The empty space between toasts lets clicks through to the page. */\n pointer-events: none;\n}\n\n.region:not(:popover-open) {\n display: none;\n}\n\n::slotted(*) {\n pointer-events: auto;\n}\n\n::slotted([data-stacked]) {\n display: none;\n}\n\n:host([placement=\"bottom-right\"]) .region {\n right: var(--edge);\n bottom: var(--bottom);\n}\n\n:host([placement=\"bottom-left\"]) .region {\n bottom: var(--bottom);\n left: var(--edge);\n}\n\n:host([placement=\"bottom-center\"]) .region {\n bottom: var(--bottom);\n left: 50%;\n translate: -50% 0;\n}\n\n/* At the top, the newest toast is the highest one, and toasts come in from above. */\n:host([placement^=\"top\"]) .region {\n top: var(--edge);\n flex-direction: column-reverse;\n}\n\n:host([placement^=\"top\"]) ::slotted(*) {\n --jl-toast-enter: -8px;\n}\n\n:host([placement=\"top-right\"]) .region {\n right: var(--edge);\n}\n\n:host([placement=\"top-center\"]) .region {\n left: 50%;\n translate: -50% 0;\n}\n";
|
|
3
3
|
export { jl_toaster_default as default };
|
|
@@ -2,8 +2,8 @@ import { BASE_STYLES } from "../styles/shared.js";
|
|
|
2
2
|
import { JlElement } from "../base/jl-element.js";
|
|
3
3
|
import { jsonOf } from "../lib/attributes.js";
|
|
4
4
|
import { registerIcons } from "../lib/icons.js";
|
|
5
|
-
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
6
5
|
import { JlIcon } from "../atoms/jl-icon.js";
|
|
6
|
+
import { setOrRemove, uniqueId } from "../lib/dom.js";
|
|
7
7
|
import { allItems, isFolder, treeKeyAction, withExpanded } from "../lib/tree.js";
|
|
8
8
|
import jl_tree_default from "./jl-tree.css_raw.js";
|
|
9
9
|
import { css } from "@jadis/core";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/styles/tokens.css?raw
|
|
2
|
-
var tokens_default = "/*\n * The design tokens, as swai and swcode have them: ink and white, flat surfaces separated by lines, and one blue\n * that marks what is live, selected or waiting for a person. Custom properties cross shadow roots, so every\n * component reads them. They sit in the `jlib` layer: any unlayered rule of the page overrides them.\n */\n@layer jlib {\n :root,\n [data-theme=\"light\"] {\n color-scheme: light;\n --jl-font-sans: \"Manrope Variable\", \"Manrope\", system-ui, -apple-system, \"Segoe UI\", sans-serif;\n --jl-font-mono: \"JetBrains Mono Variable\", \"JetBrains Mono\", ui-monospace, \"SF Mono\", Menlo, monospace;\n\n --jl-font-xs: 12px;\n --jl-font-sm: 13px;\n --jl-font-md: 14px;\n --jl-font-lg: 16px;\n --jl-font-xl: 20px;\n --jl-font-2xl: 28px;\n\n --jl-text: #0b0b0c;\n --jl-text-2: #3a3f47;\n /* Secondary text: 6.2:1 on white. */\n --jl-muted: #5b616b;\n /* Icons and decorations only: 3.2:1 on white is enough for them, not for text. */\n --jl-faint: #8a9099;\n\n --jl-bg: #ffffff;\n --jl-surface: #ffffff;\n --jl-surface-2: #f7f8f9;\n --jl-surface-3: #eef0f2;\n --jl-code-bg: #f0f2f4;\n --jl-line: #e6e8eb;\n --jl-line-soft: #eef0f2;\n --jl-line-strong: #d5d9de;\n\n /* The SyWare logo's blue: marks, focus rings, progress. 3.8:1 on white: enough for shapes, never for text. */\n --jl-brand: #0e88d3;\n /* The same hue, deep enough to carry text: buttons, links, the selection. 5.2:1 on white. */\n --jl-accent: #0c72b0;\n --jl-accent-strong: #095a8b;\n --jl-accent-soft: #e9f4fb;\n --jl-accent-line: #b7dbf2;\n --jl-on-accent: #ffffff;\n\n --jl-ok: #17784a;\n --jl-ok-soft: #ecf6f0;\n --jl-warn: #9a5b00;\n --jl-warn-soft: #fcf4e6;\n --jl-danger: #b42318;\n --jl-danger-soft: #fdf0ef;\n --jl-on-danger: #ffffff;\n --jl-info: #0c72b0;\n --jl-info-soft: #e9f4fb;\n\n /* Code: the accent for keywords, quiet colours from the same family for the rest. */\n --jl-code-keyword: #0c72b0;\n --jl-code-tag: #095a8b;\n --jl-code-attribute: #5b48c8;\n --jl-code-string: #17784a;\n --jl-code-number: #9a5b00;\n --jl-code-function: #3d5a80;\n --jl-code-property: #127a72;\n --jl-code-comment: #8a9099;\n\n --jl-radius-xs: 6px;\n --jl-radius-sm: 8px;\n --jl-radius: 10px;\n --jl-radius-lg: 12px;\n --jl-radius-xl: 20px;\n --jl-radius-pill: 999px;\n\n /* Spacing: a 4px grid, for the layouts pages build around the components. */\n --jl-space-1: 4px;\n --jl-space-2: 8px;\n --jl-space-3: 12px;\n --jl-space-4: 16px;\n --jl-space-5: 20px;\n --jl-space-6: 24px;\n --jl-space-8: 32px;\n --jl-space-10: 40px;\n --jl-space-12: 48px;\n --jl-space-16: 64px;\n\n --jl-control-sm: 30px;\n --jl-control-md: 36px;\n --jl-control-lg: 44px;\n /* The text people type in fields. */\n --jl-control-font: var(--jl-font-md);\n\n /* The widest a page gets: a form, most pages, and the tables and grids that need the room. */\n --jl-page-form: 720px;\n --jl-page-standard: 1120px;\n --jl-page-wide: 1400px;\n\n /* Flat: lines separate; only what floats (menus, dialogs, toasts) casts a shadow. */\n --jl-shadow-sm: 0 1px 2px rgb(11 11 12 / 0.05);\n --jl-shadow: 0 6px 16px -6px rgb(11 11 12 / 0.12);\n --jl-shadow-lg: 0 18px 44px -14px rgb(11 11 12 / 0.22);\n --jl-focus-ring: 0 0 0 3px color-mix(in srgb, var(--jl-brand) 35%, transparent);\n --jl-scrim: rgb(11 11 12 / 0.38);\n\n --jl-ease: cubic-bezier(0.2, 0.7, 0.2, 1);\n --jl-fast: 120ms;\n --jl-slow: 240ms;\n }\n\n @media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]) {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n }\n\n /* Dark: the same blue, lifted to read on a dark ground, with dark text on the buttons. */\n [data-theme=\"dark\"] {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n\n /*\n * Touch screens: controls a finger can hit (44px for most), and field text phones do not zoom into when it takes\n * the focus (16px). Themed parts of a page re-declare the sizes, so they take these too.\n */\n @media (pointer: coarse) {\n :root,\n [data-theme=\"light\"],\n [data-theme=\"dark\"] {\n --jl-control-sm: 36px;\n --jl-control-md: 44px;\n --jl-control-lg: 48px;\n --jl-control-font: 16px;\n }\n }\n}\n";
|
|
2
|
+
var tokens_default = "/*\n * The design tokens, as swai and swcode have them: ink and white, flat surfaces separated by lines, and one blue\n * that marks what is live, selected or waiting for a person. Custom properties cross shadow roots, so every\n * component reads them. They sit in the `jlib` layer: any unlayered rule of the page overrides them.\n */\n@layer jlib {\n :root,\n [data-theme=\"light\"] {\n color-scheme: light;\n --jl-font-sans: \"Manrope Variable\", \"Manrope\", system-ui, -apple-system, \"Segoe UI\", sans-serif;\n --jl-font-mono: \"JetBrains Mono Variable\", \"JetBrains Mono\", ui-monospace, \"SF Mono\", Menlo, monospace;\n\n --jl-font-xs: 12px;\n --jl-font-sm: 13px;\n --jl-font-md: 14px;\n --jl-font-lg: 16px;\n --jl-font-xl: 20px;\n --jl-font-2xl: 28px;\n\n --jl-text: #0b0b0c;\n --jl-text-2: #3a3f47;\n /* Secondary text: 6.2:1 on white. */\n --jl-muted: #5b616b;\n /* Icons and decorations only: 3.2:1 on white is enough for them, not for text. */\n --jl-faint: #8a9099;\n\n --jl-bg: #ffffff;\n --jl-surface: #ffffff;\n --jl-surface-2: #f7f8f9;\n --jl-surface-3: #eef0f2;\n --jl-code-bg: #f0f2f4;\n --jl-line: #e6e8eb;\n --jl-line-soft: #eef0f2;\n --jl-line-strong: #d5d9de;\n\n /* The SyWare logo's blue: marks, focus rings, progress. 3.8:1 on white: enough for shapes, never for text. */\n --jl-brand: #0e88d3;\n /* The same hue, deep enough to carry text: buttons, links, the selection. 5.2:1 on white. */\n --jl-accent: #0c72b0;\n --jl-accent-strong: #095a8b;\n --jl-accent-soft: #e9f4fb;\n --jl-accent-line: #b7dbf2;\n --jl-on-accent: #ffffff;\n /* What is drawn on the brand's blue, such as an app's icon: white in both themes, as a favicon is. */\n --jl-on-brand: #ffffff;\n\n --jl-ok: #17784a;\n --jl-ok-soft: #ecf6f0;\n --jl-warn: #9a5b00;\n --jl-warn-soft: #fcf4e6;\n --jl-danger: #b42318;\n --jl-danger-soft: #fdf0ef;\n --jl-on-danger: #ffffff;\n --jl-info: #0c72b0;\n --jl-info-soft: #e9f4fb;\n\n /* Code: the accent for keywords, quiet colours from the same family for the rest. */\n --jl-code-keyword: #0c72b0;\n --jl-code-tag: #095a8b;\n --jl-code-attribute: #5b48c8;\n --jl-code-string: #17784a;\n --jl-code-number: #9a5b00;\n --jl-code-function: #3d5a80;\n --jl-code-property: #127a72;\n --jl-code-comment: #8a9099;\n\n --jl-radius-xs: 6px;\n --jl-radius-sm: 8px;\n --jl-radius: 10px;\n --jl-radius-lg: 12px;\n --jl-radius-xl: 20px;\n --jl-radius-pill: 999px;\n\n /* Spacing: a 4px grid, for the layouts pages build around the components. */\n --jl-space-1: 4px;\n --jl-space-2: 8px;\n --jl-space-3: 12px;\n --jl-space-4: 16px;\n --jl-space-5: 20px;\n --jl-space-6: 24px;\n --jl-space-8: 32px;\n --jl-space-10: 40px;\n --jl-space-12: 48px;\n --jl-space-16: 64px;\n\n --jl-control-sm: 30px;\n --jl-control-md: 36px;\n --jl-control-lg: 44px;\n /* The text people type in fields. */\n --jl-control-font: var(--jl-font-md);\n\n /* The widest a page gets: a form, most pages, and the tables and grids that need the room. */\n --jl-page-form: 720px;\n --jl-page-standard: 1120px;\n --jl-page-wide: 1400px;\n\n /* Flat: lines separate; only what floats (menus, dialogs, toasts) casts a shadow. */\n --jl-shadow-sm: 0 1px 2px rgb(11 11 12 / 0.05);\n --jl-shadow: 0 6px 16px -6px rgb(11 11 12 / 0.12);\n --jl-shadow-lg: 0 18px 44px -14px rgb(11 11 12 / 0.22);\n --jl-focus-ring: 0 0 0 3px color-mix(in srgb, var(--jl-brand) 35%, transparent);\n --jl-scrim: rgb(11 11 12 / 0.38);\n\n --jl-ease: cubic-bezier(0.2, 0.7, 0.2, 1);\n --jl-fast: 120ms;\n --jl-slow: 240ms;\n }\n\n @media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]) {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n }\n\n /* Dark: the same blue, lifted to read on a dark ground, with dark text on the buttons. */\n [data-theme=\"dark\"] {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n\n /*\n * Touch screens: controls a finger can hit (44px for most), and field text phones do not zoom into when it takes\n * the focus (16px). Themed parts of a page re-declare the sizes, so they take these too.\n */\n @media (pointer: coarse) {\n :root,\n [data-theme=\"light\"],\n [data-theme=\"dark\"] {\n --jl-control-sm: 36px;\n --jl-control-md: 44px;\n --jl-control-lg: 48px;\n --jl-control-font: 16px;\n }\n }\n}\n";
|
|
3
3
|
export { tokens_default as default };
|
|
@@ -4,7 +4,9 @@ import { JlElement } from '../base/jl-element';
|
|
|
4
4
|
* on its own, and an optional panel on the right (`aside`). Narrower than 960 pixels, the sidebar becomes a drawer
|
|
5
5
|
* over the content, opened by a menu button in the top bar (or `nav-open`, or `toggleNav()`), the panel hides, and
|
|
6
6
|
* a bar along the bottom shows (`tabs`, such as a `jl-tab-bar`, whose `more` opens the drawer).
|
|
7
|
-
* It takes the height of its container: give that one a height (`100dvh` for a whole page).
|
|
7
|
+
* It takes the height of its container: give that one a height (`100dvh` for a whole page). A shell that fills the
|
|
8
|
+
* window writes the height of its tab bar, while it shows, as `--jl-shell-bottom` on the document: toasts keep
|
|
9
|
+
* above it, and a page's floating bars can (`bottom: calc(var(--jl-shell-bottom, 0px) + 16px)`).
|
|
8
10
|
*/
|
|
9
11
|
export declare class JlAppShell extends JlElement {
|
|
10
12
|
static readonly selector = "jl-app-shell";
|
|
@@ -25,6 +27,9 @@ export declare class JlAppShell extends JlElement {
|
|
|
25
27
|
templateCss(): string;
|
|
26
28
|
onConnect(): void;
|
|
27
29
|
onDisconnect(): void;
|
|
30
|
+
/** Tells the page how much the tab bar covers at the bottom of the window, while it shows. */
|
|
31
|
+
private renderShellBottom;
|
|
32
|
+
private withdrawShellBottom;
|
|
28
33
|
/** Whether the shell is narrow: the menu button shows only then. */
|
|
29
34
|
private isNarrow;
|
|
30
35
|
private onMenu;
|
|
@@ -10,6 +10,7 @@ import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
|
10
10
|
registerIcons({ menu: Menu });
|
|
11
11
|
var MENU_ICON_SIZE = 18;
|
|
12
12
|
var HIDDEN = "none";
|
|
13
|
+
var SHELL_BOTTOM = "--jl-shell-bottom";
|
|
13
14
|
/** Whether a click inside the drawer followed a link: the page changes, so the drawer gets out of the way. */
|
|
14
15
|
var followsLink = (event) => event.composedPath().some((node) => node instanceof HTMLAnchorElement && node.href !== "");
|
|
15
16
|
/**
|
|
@@ -17,7 +18,9 @@ var followsLink = (event) => event.composedPath().some((node) => node instanceof
|
|
|
17
18
|
* on its own, and an optional panel on the right (`aside`). Narrower than 960 pixels, the sidebar becomes a drawer
|
|
18
19
|
* over the content, opened by a menu button in the top bar (or `nav-open`, or `toggleNav()`), the panel hides, and
|
|
19
20
|
* a bar along the bottom shows (`tabs`, such as a `jl-tab-bar`, whose `more` opens the drawer).
|
|
20
|
-
* It takes the height of its container: give that one a height (`100dvh` for a whole page).
|
|
21
|
+
* It takes the height of its container: give that one a height (`100dvh` for a whole page). A shell that fills the
|
|
22
|
+
* window writes the height of its tab bar, while it shows, as `--jl-shell-bottom` on the document: toasts keep
|
|
23
|
+
* above it, and a page's floating bars can (`bottom: calc(var(--jl-shell-bottom, 0px) + 16px)`).
|
|
21
24
|
*/
|
|
22
25
|
var JlAppShell = class extends JlElement {
|
|
23
26
|
static selector = "jl-app-shell";
|
|
@@ -26,9 +29,13 @@ var JlAppShell = class extends JlElement {
|
|
|
26
29
|
navOpen = this.useChange(false, (value) => this.renderNavOpen(value), { attribute: "nav-open" });
|
|
27
30
|
_state = {
|
|
28
31
|
navListeners: new AbortController(),
|
|
32
|
+
publishedBottom: false,
|
|
29
33
|
tabsListeners: new AbortController()
|
|
30
34
|
};
|
|
31
|
-
_resize = new ResizeObserver(() =>
|
|
35
|
+
_resize = new ResizeObserver(() => {
|
|
36
|
+
this.renderInert();
|
|
37
|
+
this.renderShellBottom();
|
|
38
|
+
});
|
|
32
39
|
_refs = this.useRefs((ref) => ({
|
|
33
40
|
aside: ref(".aside"),
|
|
34
41
|
asideSlot: ref("slot[name=\"aside\"]"),
|
|
@@ -96,6 +103,7 @@ var JlAppShell = class extends JlElement {
|
|
|
96
103
|
}
|
|
97
104
|
onConnect() {
|
|
98
105
|
this._resize.observe(this);
|
|
106
|
+
this._resize.observe(this._refs.tabs);
|
|
99
107
|
this.on(this._refs.menu, "click", () => this.onMenu());
|
|
100
108
|
this.on(this._refs.scrim, "click", () => this.setNavOpen(false));
|
|
101
109
|
this.on(this._refs.nav, "click", (event) => {
|
|
@@ -114,6 +122,23 @@ var JlAppShell = class extends JlElement {
|
|
|
114
122
|
this._resize.disconnect();
|
|
115
123
|
this._state.navListeners.abort();
|
|
116
124
|
this._state.tabsListeners.abort();
|
|
125
|
+
this.withdrawShellBottom();
|
|
126
|
+
}
|
|
127
|
+
/** Tells the page how much the tab bar covers at the bottom of the window, while it shows. */
|
|
128
|
+
renderShellBottom() {
|
|
129
|
+
const height = Math.round(this._refs.tabs.getBoundingClientRect().height);
|
|
130
|
+
const fillsWindow = this.getBoundingClientRect().bottom >= window.innerHeight - 1;
|
|
131
|
+
if (height === 0 || !fillsWindow) {
|
|
132
|
+
this.withdrawShellBottom();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
document.documentElement.style.setProperty(SHELL_BOTTOM, `${height}px`);
|
|
136
|
+
this._state.publishedBottom = true;
|
|
137
|
+
}
|
|
138
|
+
withdrawShellBottom() {
|
|
139
|
+
if (!this._state.publishedBottom) return;
|
|
140
|
+
document.documentElement.style.removeProperty(SHELL_BOTTOM);
|
|
141
|
+
this._state.publishedBottom = false;
|
|
117
142
|
}
|
|
118
143
|
/** Whether the shell is narrow: the menu button shows only then. */
|
|
119
144
|
isNarrow() {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/templates/jl-auth-layout.css?raw
|
|
2
|
+
var jl_auth_layout_default = ":host {\n display: block;\n min-height: var(--min-height, 100dvh);\n}\n\n.screen {\n display: grid;\n grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);\n min-height: var(--min-height, 100dvh);\n}\n\n/* The brand's dark panel: the dark tokens apply inside it (data-theme), whatever the page's theme. */\n.story {\n position: relative;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n gap: 32px;\n overflow: hidden;\n padding: 40px 48px;\n background: var(--jl-bg);\n color: var(--jl-text);\n}\n\n.brand,\n.pitch,\n.points,\n.origin {\n position: relative;\n z-index: 1;\n}\n\n.pitch {\n display: grid;\n gap: 16px;\n max-width: 520px;\n}\n\n.headline {\n font-size: clamp(30px, 3.4vw, 46px);\n font-weight: 800;\n letter-spacing: -0.03em;\n line-height: 1.08;\n text-wrap: balance;\n}\n\n.accent {\n color: var(--jl-brand);\n}\n\n.text {\n color: var(--jl-muted);\n font-size: 15.5px;\n line-height: 1.6;\n}\n\n.points {\n display: grid;\n gap: 10px;\n margin: 0;\n padding: 0;\n list-style: none;\n font-size: var(--jl-font-md);\n}\n\n.points li {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.tick {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--jl-brand);\n color: var(--jl-on-brand);\n}\n\n.origin {\n color: var(--jl-muted);\n font-size: var(--jl-font-xs);\n font-weight: 650;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n/* The SyWare mark, large and faint, leaning out of the corner. */\n.backdrop {\n position: absolute;\n right: -90px;\n bottom: -110px;\n width: 420px;\n height: 460px;\n opacity: 0.07;\n pointer-events: none;\n}\n\n.side {\n display: grid;\n place-items: center;\n padding: 32px 24px;\n background: var(--jl-bg);\n}\n\n/* A phone: the panel is a band with the brand, above the form. */\n@media (max-width: 860px) {\n .screen {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n\n .story {\n padding: 18px 24px;\n }\n\n .pitch,\n .points,\n .origin,\n .backdrop {\n display: none;\n }\n}\n";
|
|
3
|
+
export { jl_auth_layout_default as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
/**
|
|
3
|
+
* The screen before an app, as every SyWare app shows it: on a dark panel, the app's brand (slot `brand`), a
|
|
4
|
+
* headline whose words between asterisks take the brand's blue ("Workflows that *ask* before they act."), a
|
|
5
|
+
* sentence, a few points, and where it comes from; beside it, the form (the default slot). On a phone, the panel
|
|
6
|
+
* becomes a band with the brand, above the form.
|
|
7
|
+
*/
|
|
8
|
+
export declare class JlAuthLayout extends JlElement {
|
|
9
|
+
static readonly selector = "jl-auth-layout";
|
|
10
|
+
/** What the app does, in a few words; `*words*` take the brand's blue. */
|
|
11
|
+
readonly pitch: Readonly<Readonly<{
|
|
12
|
+
get(): string;
|
|
13
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
14
|
+
}>>;
|
|
15
|
+
/** One or two sentences under the headline. */
|
|
16
|
+
readonly text: Readonly<Readonly<{
|
|
17
|
+
get(): string;
|
|
18
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
19
|
+
}>>;
|
|
20
|
+
/** What the app is good at, three points at most; HTML writes them as JSON. */
|
|
21
|
+
readonly points: Readonly<Readonly<{
|
|
22
|
+
get(): string[];
|
|
23
|
+
set(setter: string[] | ((prevState: string[]) => string[])): void;
|
|
24
|
+
}>>;
|
|
25
|
+
/** Where the app comes from, at the foot of the panel. */
|
|
26
|
+
readonly origin: Readonly<Readonly<{
|
|
27
|
+
get(): string;
|
|
28
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
29
|
+
}>>;
|
|
30
|
+
private readonly _refs;
|
|
31
|
+
templateHtml(): Node;
|
|
32
|
+
templateCss(): string;
|
|
33
|
+
private renderPitch;
|
|
34
|
+
private renderPoints;
|
|
35
|
+
}
|