@hypermedia-components/core 0.1.0 → 0.1.2
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/csrf-header.d.ts +25 -0
- package/dist/csrf-header.js +83 -0
- package/dist/datagrid.js +58 -11
- package/dist/field-errors.js +29 -5
- package/dist/hc-combobox.css +1 -1
- package/dist/hc-command.css +1 -1
- package/dist/hc-datagrid.css +3 -3
- package/dist/hc-dialog.css +1 -1
- package/dist/hc-drawer.css +1 -1
- package/dist/hc-hovercard.css +1 -1
- package/dist/hc-menu.css +1 -1
- package/dist/hc-multicombobox.css +1 -1
- package/dist/hc-navmenu.css +1 -1
- package/dist/hc-popover.css +1 -1
- package/dist/hc-switch.css +1 -1
- package/dist/hc-tabs.css +2 -2
- package/dist/hc-toast.css +1 -1
- package/dist/hc.behaviors.d.ts +2 -1
- package/dist/hc.behaviors.js +3 -0
- package/dist/hc.behaviors.min.js +2 -2
- package/dist/hc.core.css +10 -0
- package/dist/hc.core.min.css +1 -1
- package/dist/hc.css +26 -16
- package/dist/hc.min.css +1 -1
- package/dist/hc.min.js +2 -2
- package/dist/hc.tokens.core.css +10 -0
- package/dist/hc.tokens.css +10 -0
- package/dist/i18n.js +15 -8
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/locales/ja.d.ts +3 -0
- package/dist/locales/ja.js +44 -0
- package/package.json +11 -6
- package/src/tokens/README.md +9 -1
- package/src/tokens/semantic.tokens.json +8 -0
- package/src/tokens/theme.dark.tokens.json +8 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install the csrf-header behavior: attach the page's CSRF token
|
|
3
|
+
* (`<meta name="csrf-token" content="…">`, header name from the meta's
|
|
4
|
+
* `data-header` attribute, default `X-CSRF-Token`) to every htmx
|
|
5
|
+
* request via `htmx:configRequest`.
|
|
6
|
+
*
|
|
7
|
+
* The meta tag is read at request time, so a rotated token is picked
|
|
8
|
+
* up automatically. A header already set on the request (e.g. via
|
|
9
|
+
* `data-hx-headers`) is left untouched. Without the meta tag the
|
|
10
|
+
* behavior is inert.
|
|
11
|
+
*
|
|
12
|
+
* @param {Document} [root]
|
|
13
|
+
* The root to listen on. Defaults to the global document when
|
|
14
|
+
* available.
|
|
15
|
+
* @returns {() => void} an idempotent uninstaller.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // <head>
|
|
19
|
+
* // <meta name="csrf-token" content="3x4mpl3…">
|
|
20
|
+
* // </head>
|
|
21
|
+
*
|
|
22
|
+
* import { installCsrfHeader } from '@hypermedia-components/core';
|
|
23
|
+
* installCsrfHeader();
|
|
24
|
+
*/
|
|
25
|
+
export function installCsrfHeader(root?: Document): () => void;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// csrf-header behavior — the blessed CSRF token delivery convention for
|
|
2
|
+
// htmx requests (#246).
|
|
3
|
+
//
|
|
4
|
+
// Contract:
|
|
5
|
+
// - The server's layout renders the token into the page head:
|
|
6
|
+
//
|
|
7
|
+
// <meta name="csrf-token" content="…">
|
|
8
|
+
//
|
|
9
|
+
// The header name defaults to `X-CSRF-Token` and is configurable on
|
|
10
|
+
// the carrier for stacks that expect a different one:
|
|
11
|
+
//
|
|
12
|
+
// <meta name="csrf-token" content="…" data-header="X-CSRFToken">
|
|
13
|
+
//
|
|
14
|
+
// - On every `htmx:configRequest` the behavior reads the meta tag —
|
|
15
|
+
// at request time, so server-side token rotation needs no
|
|
16
|
+
// re-install — and adds the header to the outgoing request.
|
|
17
|
+
// - A header already present in `event.detail.headers` is never
|
|
18
|
+
// overwritten: a per-request `data-hx-headers` (or an earlier
|
|
19
|
+
// listener) wins over the page-level convention.
|
|
20
|
+
// - No meta tag, or an empty `content` → strict no-op.
|
|
21
|
+
//
|
|
22
|
+
// The behavior never makes a request — htmx owns the network. Plain
|
|
23
|
+
// `<form method="post">` submissions never fire `htmx:configRequest`;
|
|
24
|
+
// no-JS degradation needs the framework's hidden-field mechanism.
|
|
25
|
+
//
|
|
26
|
+
// installCsrfHeader() returns an `uninstall` function. Idempotent.
|
|
27
|
+
|
|
28
|
+
const INSTALL_KEY = '__hcCsrfHeaderUninstall';
|
|
29
|
+
|
|
30
|
+
const DEFAULT_HEADER = 'X-CSRF-Token';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Install the csrf-header behavior: attach the page's CSRF token
|
|
34
|
+
* (`<meta name="csrf-token" content="…">`, header name from the meta's
|
|
35
|
+
* `data-header` attribute, default `X-CSRF-Token`) to every htmx
|
|
36
|
+
* request via `htmx:configRequest`.
|
|
37
|
+
*
|
|
38
|
+
* The meta tag is read at request time, so a rotated token is picked
|
|
39
|
+
* up automatically. A header already set on the request (e.g. via
|
|
40
|
+
* `data-hx-headers`) is left untouched. Without the meta tag the
|
|
41
|
+
* behavior is inert.
|
|
42
|
+
*
|
|
43
|
+
* @param {Document} [root]
|
|
44
|
+
* The root to listen on. Defaults to the global document when
|
|
45
|
+
* available.
|
|
46
|
+
* @returns {() => void} an idempotent uninstaller.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // <head>
|
|
50
|
+
* // <meta name="csrf-token" content="3x4mpl3…">
|
|
51
|
+
* // </head>
|
|
52
|
+
*
|
|
53
|
+
* import { installCsrfHeader } from '@hypermedia-components/core';
|
|
54
|
+
* installCsrfHeader();
|
|
55
|
+
*/
|
|
56
|
+
export function installCsrfHeader(root = (typeof document !== 'undefined' ? document : null)) {
|
|
57
|
+
if (!root) return () => {};
|
|
58
|
+
if (root[INSTALL_KEY]) return root[INSTALL_KEY];
|
|
59
|
+
|
|
60
|
+
function onConfigRequest(event) {
|
|
61
|
+
const headers = event?.detail?.headers;
|
|
62
|
+
if (!headers || typeof headers !== 'object') return;
|
|
63
|
+
|
|
64
|
+
const doc = root.nodeType === 9 ? root : root.ownerDocument;
|
|
65
|
+
const meta = doc.querySelector('meta[name="csrf-token"]');
|
|
66
|
+
const token = meta?.getAttribute('content');
|
|
67
|
+
if (!token) return;
|
|
68
|
+
|
|
69
|
+
const header = meta.getAttribute('data-header') || DEFAULT_HEADER;
|
|
70
|
+
if (header in headers) return; // an explicit per-request header wins
|
|
71
|
+
headers[header] = token;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
root.addEventListener('htmx:configRequest', onConfigRequest);
|
|
75
|
+
|
|
76
|
+
const uninstall = () => {
|
|
77
|
+
if (root[INSTALL_KEY] !== uninstall) return;
|
|
78
|
+
root.removeEventListener('htmx:configRequest', onConfigRequest);
|
|
79
|
+
delete root[INSTALL_KEY];
|
|
80
|
+
};
|
|
81
|
+
root[INSTALL_KEY] = uninstall;
|
|
82
|
+
return uninstall;
|
|
83
|
+
}
|
package/dist/datagrid.js
CHANGED
|
@@ -80,6 +80,32 @@ function rowCells(row) {
|
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// The navigation matrix as a VISUAL grid: a cell with rowspan/colspan is
|
|
84
|
+
// entered into every (row, column) slot it covers, so arrow keys move by
|
|
85
|
+
// visual position and multi-row records stay column-aligned (the lead
|
|
86
|
+
// rowspan cell is reachable from every sub-row it spans).
|
|
87
|
+
function buildMatrix(grid) {
|
|
88
|
+
const rows = bodyRows(grid);
|
|
89
|
+
const out = rows.map(() => []);
|
|
90
|
+
rows.forEach((row, r) => {
|
|
91
|
+
let c = 0;
|
|
92
|
+
for (const cell of rowCells(row)) {
|
|
93
|
+
while (out[r][c] !== undefined) c += 1; // slot taken by a rowspan above
|
|
94
|
+
const cs = cell.colSpan || 1;
|
|
95
|
+
// rowspan="0" = "to the end of the row group" (HTML spec); either way
|
|
96
|
+
// a span never crosses into the next record's rows.
|
|
97
|
+
const rs = cell.rowSpan === 0 ? rows.length - r : cell.rowSpan || 1;
|
|
98
|
+
for (let dr = 0; dr < rs; dr += 1) {
|
|
99
|
+
const target = rows[r + dr];
|
|
100
|
+
if (!target || target.parentNode !== row.parentNode) break;
|
|
101
|
+
for (let dc = 0; dc < cs; dc += 1) out[r + dr][c + dc] = cell;
|
|
102
|
+
}
|
|
103
|
+
c += cs;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
|
|
83
109
|
/** Measure header heights + frozen widths → sticky offset variables. */
|
|
84
110
|
function measure(grid) {
|
|
85
111
|
const headTrs = ownedBy(grid, '.hc-datagrid__head > tr');
|
|
@@ -149,7 +175,8 @@ function attach(grid, detachers) {
|
|
|
149
175
|
for (const h of ownedBy(grid, '.hc-datagrid__headcell')) {
|
|
150
176
|
if (!h.getAttribute('role')) h.setAttribute('role', 'columnheader');
|
|
151
177
|
}
|
|
152
|
-
matrix
|
|
178
|
+
// A spanning cell occupies several matrix slots — visit each cell once.
|
|
179
|
+
new Set(matrix.flat()).forEach((cell) => {
|
|
153
180
|
cell.setAttribute('role', cell.tagName === 'TH' ? 'rowheader' : 'gridcell');
|
|
154
181
|
cell.tabIndex = -1;
|
|
155
182
|
// Widgets in cells are not separate tab stops — the grid manages focus.
|
|
@@ -160,15 +187,16 @@ function attach(grid, detachers) {
|
|
|
160
187
|
}
|
|
161
188
|
|
|
162
189
|
function rebuild() {
|
|
163
|
-
matrix =
|
|
190
|
+
matrix = buildMatrix(grid);
|
|
164
191
|
applyRoles();
|
|
165
192
|
applyResizedWidths(); // re-apply column widths to swapped-in rows
|
|
166
|
-
|
|
167
|
-
if (cur) {
|
|
168
|
-
cur
|
|
169
|
-
const pos = locate(cur);
|
|
193
|
+
let cur = matrix[active.r]?.[active.c];
|
|
194
|
+
if (!cur) {
|
|
195
|
+
cur = matrix[0]?.[0];
|
|
196
|
+
const pos = cur && locate(cur);
|
|
170
197
|
if (pos) active = pos;
|
|
171
198
|
}
|
|
199
|
+
if (cur) cur.tabIndex = 0;
|
|
172
200
|
}
|
|
173
201
|
|
|
174
202
|
// ---- Column resize ----
|
|
@@ -331,6 +359,23 @@ function attach(grid, detachers) {
|
|
|
331
359
|
cell.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });
|
|
332
360
|
}
|
|
333
361
|
|
|
362
|
+
// Arrow movement: walk from the active slot in direction (dr, dc),
|
|
363
|
+
// skipping further slots of the same spanning cell so a rowspan/colspan
|
|
364
|
+
// cell counts as a single stop. The active slot (not the cell's top-left)
|
|
365
|
+
// is the walk origin, so the entry row/column is kept while crossing a
|
|
366
|
+
// span — ↓ then ↑ round-trips.
|
|
367
|
+
function step(dr, dc) {
|
|
368
|
+
const { r, c } = active;
|
|
369
|
+
const cur = matrix[r]?.[c];
|
|
370
|
+
let nr = r + dr;
|
|
371
|
+
let nc = c + dc;
|
|
372
|
+
while (cur && matrix[nr]?.[nc] === cur) {
|
|
373
|
+
nr += dr;
|
|
374
|
+
nc += dc;
|
|
375
|
+
}
|
|
376
|
+
setActive(nr, nc);
|
|
377
|
+
}
|
|
378
|
+
|
|
334
379
|
function toggleRow(r) {
|
|
335
380
|
const row = bodyRows(grid)[r];
|
|
336
381
|
if (!row) return;
|
|
@@ -386,10 +431,10 @@ function attach(grid, detachers) {
|
|
|
386
431
|
else if (key === 'ArrowLeft') key = 'ArrowRight';
|
|
387
432
|
}
|
|
388
433
|
switch (key) {
|
|
389
|
-
case 'ArrowDown':
|
|
390
|
-
case 'ArrowUp':
|
|
391
|
-
case 'ArrowRight':
|
|
392
|
-
case 'ArrowLeft':
|
|
434
|
+
case 'ArrowDown': step(1, 0); break;
|
|
435
|
+
case 'ArrowUp': step(-1, 0); break;
|
|
436
|
+
case 'ArrowRight': step(0, 1); break;
|
|
437
|
+
case 'ArrowLeft': step(0, -1); break;
|
|
393
438
|
case 'Home': setActive(event.ctrlKey ? 0 : r, 0); break;
|
|
394
439
|
case 'End':
|
|
395
440
|
if (event.ctrlKey) setActive(matrix.length - 1, Infinity);
|
|
@@ -419,9 +464,11 @@ function attach(grid, detachers) {
|
|
|
419
464
|
if (!cell || !grid.contains(cell)) return;
|
|
420
465
|
const pos = locate(cell);
|
|
421
466
|
if (!pos) return;
|
|
422
|
-
if (
|
|
467
|
+
if (matrix[active.r]?.[active.c] !== cell) {
|
|
423
468
|
setActive(pos.r, pos.c, false); // don't re-focus; focus is already here
|
|
424
469
|
} else {
|
|
470
|
+
// Already the active cell — keep the active slot as-is so a spanning
|
|
471
|
+
// cell remembers which sub-row/column it was entered from.
|
|
425
472
|
cell.setAttribute('data-active', '');
|
|
426
473
|
}
|
|
427
474
|
}
|
package/dist/field-errors.js
CHANGED
|
@@ -27,8 +27,11 @@
|
|
|
27
27
|
// control is focused (opt out with `data-focus="none"` on the alert).
|
|
28
28
|
//
|
|
29
29
|
// Message resolution per item: `data-message-key` found in the i18n
|
|
30
|
-
// catalog → `t(key, { field, code })`; otherwise
|
|
31
|
-
// otherwise `t('fieldErrors.unknown')`. Localize once
|
|
30
|
+
// catalog → `t(key, { field, code, ...data-message-params })`; otherwise
|
|
31
|
+
// the item's own text; otherwise `t('fieldErrors.unknown')`. Localize once
|
|
32
|
+
// via `setMessages()`. `data-message-params` is an optional JSON object of
|
|
33
|
+
// server-provided interpolation values (constraint declarations, validation
|
|
34
|
+
// row columns) for translations with placeholders beyond {field}/{code}.
|
|
32
35
|
//
|
|
33
36
|
// Server errors are stale the moment the user edits the field or
|
|
34
37
|
// resubmits: cleared on first `input`/`change` per field, on `submit` /
|
|
@@ -65,16 +68,21 @@ function scopeOf(alert, root) {
|
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
// First control in the scope whose `name` matches. `form.elements`
|
|
68
|
-
// handles radio/checkbox groups natively (RadioNodeList
|
|
71
|
+
// handles radio/checkbox groups natively (RadioNodeList). Hidden inputs
|
|
72
|
+
// are skipped when the group has a visible member: the blessed boolean
|
|
73
|
+
// idiom pairs `<input type="hidden" value="false">` with the real
|
|
74
|
+
// checkbox under one name, and the ARIA wiring, focus, and edit-to-clear
|
|
75
|
+
// belong on the control the user can operate.
|
|
69
76
|
function controlFor(scope, name) {
|
|
70
77
|
let found;
|
|
71
78
|
if (scope.elements && typeof scope.elements.namedItem === 'function') {
|
|
72
79
|
found = scope.elements.namedItem(name);
|
|
73
80
|
} else {
|
|
74
|
-
found = scope.
|
|
81
|
+
found = scope.querySelectorAll(`[name="${escapeName(name)}"]`);
|
|
75
82
|
}
|
|
76
83
|
if (found && found.tagName == null && typeof found.length === 'number') {
|
|
77
|
-
|
|
84
|
+
const members = Array.from(found); // RadioNodeList / NodeList
|
|
85
|
+
found = members.find((el) => el.type !== 'hidden') ?? members[0];
|
|
78
86
|
}
|
|
79
87
|
return found ?? null;
|
|
80
88
|
}
|
|
@@ -85,6 +93,22 @@ function resolveMessage(item) {
|
|
|
85
93
|
field: item.getAttribute('data-field') ?? '',
|
|
86
94
|
code: item.getAttribute('data-code') ?? '',
|
|
87
95
|
};
|
|
96
|
+
// Optional server-provided interpolation params (a JSON object), so a
|
|
97
|
+
// catalog translation may use placeholders beyond {field}/{code} — e.g.
|
|
98
|
+
// data-message-params='{"stock": 5}' for "在庫 {stock} を超えています。".
|
|
99
|
+
// Item params win over the implicit field/code; malformed or non-object
|
|
100
|
+
// JSON degrades to the attribute being ignored.
|
|
101
|
+
const raw = item.getAttribute('data-message-params');
|
|
102
|
+
if (raw) {
|
|
103
|
+
try {
|
|
104
|
+
const extra = JSON.parse(raw);
|
|
105
|
+
if (extra && typeof extra === 'object' && !Array.isArray(extra)) {
|
|
106
|
+
Object.assign(params, extra);
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
/* malformed JSON — keep the default params */
|
|
110
|
+
}
|
|
111
|
+
}
|
|
88
112
|
if (key && hasMessage(key)) return t(key, params);
|
|
89
113
|
const text = item.textContent.trim();
|
|
90
114
|
if (text) return text;
|
package/dist/hc-combobox.css
CHANGED
package/dist/hc-command.css
CHANGED
package/dist/hc-datagrid.css
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
/* Contextual shadow cast by a frozen column's trailing edge — its
|
|
39
39
|
direction flips per edge (see the frozen-edge rules below), so it
|
|
40
40
|
stays a CSS-local var, not a theme token. */
|
|
41
|
-
--hc-datagrid-freeze-shadow: 2px 0 4px -2px
|
|
41
|
+
--hc-datagrid-freeze-shadow: 2px 0 4px -2px var(--hc-shadow-edge);
|
|
42
42
|
|
|
43
43
|
position: relative;
|
|
44
44
|
border: 1px solid var(--hc-datagrid-border);
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
|
|
174
174
|
/* RTL: the freeze line falls on the other (inline-end) side. */
|
|
175
175
|
.hc-datagrid:dir(rtl) {
|
|
176
|
-
--hc-datagrid-freeze-shadow: -2px 0 4px -2px
|
|
176
|
+
--hc-datagrid-freeze-shadow: -2px 0 4px -2px var(--hc-shadow-edge);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
/* ---- States ----
|
|
@@ -355,7 +355,7 @@
|
|
|
355
355
|
line-height: 1.4;
|
|
356
356
|
white-space: normal;
|
|
357
357
|
overflow-wrap: anywhere;
|
|
358
|
-
box-shadow:
|
|
358
|
+
box-shadow: var(--hc-shadow-lg);
|
|
359
359
|
pointer-events: none;
|
|
360
360
|
}
|
|
361
361
|
|
package/dist/hc-dialog.css
CHANGED
package/dist/hc-drawer.css
CHANGED
package/dist/hc-hovercard.css
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
color: var(--hc-hovercard-fg);
|
|
41
41
|
inline-size: max-content;
|
|
42
42
|
max-inline-size: var(--hc-hovercard-max-width);
|
|
43
|
-
box-shadow:
|
|
43
|
+
box-shadow: var(--hc-shadow-lg);
|
|
44
44
|
|
|
45
45
|
/* Shared directional placement (hc-anchored.css). */
|
|
46
46
|
--hc-anchored-offset: var(--hc-hovercard-offset);
|
package/dist/hc-menu.css
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
color: var(--hc-menu-fg);
|
|
35
35
|
min-inline-size: var(--hc-menu-min-width);
|
|
36
36
|
max-inline-size: var(--hc-menu-max-width);
|
|
37
|
-
box-shadow:
|
|
37
|
+
box-shadow: var(--hc-shadow-lg);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/* Anchor Positioning path. installMenu injects the matching
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
min-inline-size: var(--hc-multicombobox-listbox-min-width);
|
|
118
118
|
max-block-size: var(--hc-multicombobox-listbox-max-height);
|
|
119
119
|
overflow-y: auto;
|
|
120
|
-
box-shadow:
|
|
120
|
+
box-shadow: var(--hc-shadow-lg);
|
|
121
121
|
list-style: none;
|
|
122
122
|
}
|
|
123
123
|
|
package/dist/hc-navmenu.css
CHANGED
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
background: var(--hc-navmenu-panel-bg);
|
|
78
78
|
color: var(--hc-navmenu-panel-fg);
|
|
79
79
|
min-inline-size: var(--hc-navmenu-panel-min-width);
|
|
80
|
-
box-shadow:
|
|
80
|
+
box-shadow: var(--hc-shadow-lg);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/* Links inside a panel stack as a readable list. */
|
package/dist/hc-popover.css
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
color: var(--hc-popover-fg);
|
|
15
15
|
min-inline-size: var(--hc-popover-min-width);
|
|
16
16
|
max-inline-size: var(--hc-popover-max-width);
|
|
17
|
-
box-shadow:
|
|
17
|
+
box-shadow: var(--hc-shadow-lg);
|
|
18
18
|
|
|
19
19
|
/* Shared directional placement (hc-anchored.css). Anchoring is opt-in via
|
|
20
20
|
* data-side + installPopover; a bare popover stays browser-positioned. */
|
package/dist/hc-switch.css
CHANGED
package/dist/hc-tabs.css
CHANGED
|
@@ -226,12 +226,12 @@
|
|
|
226
226
|
|
|
227
227
|
.hc-tabs__scroll[data-dir="start"] {
|
|
228
228
|
inset-inline-start: 0;
|
|
229
|
-
box-shadow: 4px 0 6px -4px
|
|
229
|
+
box-shadow: 4px 0 6px -4px var(--hc-shadow-edge);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
.hc-tabs__scroll[data-dir="end"] {
|
|
233
233
|
inset-inline-end: 0;
|
|
234
|
-
box-shadow: -4px 0 6px -4px
|
|
234
|
+
box-shadow: -4px 0 6px -4px var(--hc-shadow-edge);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
.hc-tabs__scroll::before {
|
package/dist/hc-toast.css
CHANGED
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
border: 1px solid var(--hc-toast-info-border);
|
|
67
67
|
background: var(--hc-toast-info-bg);
|
|
68
68
|
color: var(--hc-toast-info-fg);
|
|
69
|
-
box-shadow:
|
|
69
|
+
box-shadow: var(--hc-shadow-md);
|
|
70
70
|
|
|
71
71
|
/* Horizontal drag is the swipe-to-dismiss gesture; the behavior animates
|
|
72
72
|
* the snap-back / fly-out via these transitions. */
|
package/dist/hc.behaviors.d.ts
CHANGED
|
@@ -29,5 +29,6 @@ import { installDatagrid } from './datagrid.js';
|
|
|
29
29
|
import { installValidation } from './validation.js';
|
|
30
30
|
import { installThemeToggle } from './theme-toggle.js';
|
|
31
31
|
import { installFieldErrors } from './field-errors.js';
|
|
32
|
-
|
|
32
|
+
import { installCsrfHeader } from './csrf-header.js';
|
|
33
|
+
export { installConfirm, installToast, installCloseDialog, installClosePopover, installRemoteDialog, installTabs, installMenu, installMenubar, installNavmenu, installTooltip, installPopover, installSlider, installCombobox, installMulticombobox, installDrawer, installHovercard, installToggleGroup, installCarousel, installToolbar, installAvatar, installPasswordToggle, installContextMenu, installCommand, installCalendar, installInputOtp, installSplitter, installShell, installDatagrid, installValidation, installThemeToggle, installFieldErrors, installCsrfHeader };
|
|
33
34
|
export { setMessages, resetMessages, getMessages, hasMessage, DEFAULT_MESSAGES } from "./i18n.js";
|
package/dist/hc.behaviors.js
CHANGED
|
@@ -38,6 +38,7 @@ import { installDatagrid } from './datagrid.js';
|
|
|
38
38
|
import { installValidation } from './validation.js';
|
|
39
39
|
import { installThemeToggle } from './theme-toggle.js';
|
|
40
40
|
import { installFieldErrors } from './field-errors.js';
|
|
41
|
+
import { installCsrfHeader } from './csrf-header.js';
|
|
41
42
|
|
|
42
43
|
function init() {
|
|
43
44
|
installConfirm();
|
|
@@ -71,6 +72,7 @@ function init() {
|
|
|
71
72
|
installValidation();
|
|
72
73
|
installThemeToggle();
|
|
73
74
|
installFieldErrors();
|
|
75
|
+
installCsrfHeader();
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
if (typeof document !== 'undefined') {
|
|
@@ -113,6 +115,7 @@ export {
|
|
|
113
115
|
installValidation,
|
|
114
116
|
installThemeToggle,
|
|
115
117
|
installFieldErrors,
|
|
118
|
+
installCsrfHeader,
|
|
116
119
|
};
|
|
117
120
|
|
|
118
121
|
// i18n — set the locale before this module's auto-init runs (e.g. inline
|