@icen.ai/ui 0.8.0 → 0.9.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/AGENTS.md +63 -14
- package/README.md +17 -9
- package/dist/base.css +4 -3
- package/dist/behaviors/accordion.d.mts +5 -2
- package/dist/behaviors/accordion.mjs +36 -11
- package/dist/behaviors/ai-branch.d.mts +19 -0
- package/dist/behaviors/ai-branch.mjs +217 -0
- package/dist/behaviors/ai-chat.d.mts +11 -7
- package/dist/behaviors/ai-chat.mjs +134 -51
- package/dist/behaviors/ai-composer.d.mts +28 -3
- package/dist/behaviors/ai-composer.mjs +399 -229
- package/dist/behaviors/ai-core.d.mts +9 -4
- package/dist/behaviors/ai-core.mjs +21 -8
- package/dist/behaviors/ai-diff.d.mts +2 -2
- package/dist/behaviors/ai-diff.mjs +172 -41
- package/dist/behaviors/ai-feedback.d.mts +26 -0
- package/dist/behaviors/ai-feedback.mjs +303 -0
- package/dist/behaviors/ai-panel.d.mts +26 -9
- package/dist/behaviors/ai-panel.mjs +211 -110
- package/dist/behaviors/ai-provider.mjs +54 -48
- package/dist/behaviors/ai-threads.d.mts +38 -0
- package/dist/behaviors/ai-threads.mjs +319 -0
- package/dist/behaviors/ai-tool.d.mts +12 -4
- package/dist/behaviors/ai-tool.mjs +316 -263
- package/dist/behaviors/ai-tools.d.mts +9 -6
- package/dist/behaviors/ai-tools.mjs +264 -155
- package/dist/behaviors/back-top.mjs +16 -1
- package/dist/behaviors/carousel.d.mts +5 -2
- package/dist/behaviors/carousel.mjs +53 -26
- package/dist/behaviors/charts.d.mts +170 -22
- package/dist/behaviors/charts.mjs +1016 -150
- package/dist/behaviors/command-palette.d.mts +40 -6
- package/dist/behaviors/command-palette.mjs +143 -15
- package/dist/behaviors/context-menu.d.mts +21 -4
- package/dist/behaviors/context-menu.mjs +122 -38
- package/dist/behaviors/controls.d.mts +59 -0
- package/dist/behaviors/controls.mjs +601 -0
- package/dist/behaviors/copy.d.mts +5 -2
- package/dist/behaviors/copy.mjs +37 -12
- package/dist/behaviors/datatable.d.mts +12 -0
- package/dist/behaviors/datatable.mjs +226 -43
- package/dist/behaviors/date-picker.d.mts +2 -2
- package/dist/behaviors/date-picker.mjs +171 -32
- package/dist/behaviors/dropdown.d.mts +6 -2
- package/dist/behaviors/dropdown.mjs +164 -25
- package/dist/behaviors/events.d.mts +523 -0
- package/dist/behaviors/events.mjs +208 -0
- package/dist/behaviors/input.mjs +25 -12
- package/dist/behaviors/kb-access.d.mts +34 -0
- package/dist/behaviors/kb-access.mjs +569 -0
- package/dist/behaviors/kb-acl.d.mts +50 -0
- package/dist/behaviors/kb-acl.mjs +405 -0
- package/dist/behaviors/kb-answer.d.mts +38 -0
- package/dist/behaviors/kb-answer.mjs +2055 -0
- package/dist/behaviors/kb-audit.d.mts +23 -0
- package/dist/behaviors/kb-audit.mjs +375 -0
- package/dist/behaviors/kb-canvas.d.mts +44 -0
- package/dist/behaviors/kb-canvas.mjs +589 -0
- package/dist/behaviors/kb-chain.d.mts +15 -0
- package/dist/behaviors/kb-chain.mjs +270 -0
- package/dist/behaviors/kb-checkpoint.d.mts +16 -0
- package/dist/behaviors/kb-checkpoint.mjs +342 -0
- package/dist/behaviors/kb-chunks.d.mts +31 -0
- package/dist/behaviors/kb-chunks.mjs +475 -0
- package/dist/behaviors/kb-citation.d.mts +38 -0
- package/dist/behaviors/kb-citation.mjs +677 -0
- package/dist/behaviors/kb-clarify.d.mts +20 -0
- package/dist/behaviors/kb-clarify.mjs +248 -0
- package/dist/behaviors/kb-conflict.d.mts +22 -0
- package/dist/behaviors/kb-conflict.mjs +284 -0
- package/dist/behaviors/kb-connector.d.mts +17 -0
- package/dist/behaviors/kb-connector.mjs +375 -0
- package/dist/behaviors/kb-core.d.mts +529 -0
- package/dist/behaviors/kb-core.mjs +890 -0
- package/dist/behaviors/kb-eval.d.mts +22 -0
- package/dist/behaviors/kb-eval.mjs +408 -0
- package/dist/behaviors/kb-explain.d.mts +11 -0
- package/dist/behaviors/kb-explain.mjs +243 -0
- package/dist/behaviors/kb-filter.d.mts +31 -0
- package/dist/behaviors/kb-filter.mjs +587 -0
- package/dist/behaviors/kb-gap.d.mts +27 -0
- package/dist/behaviors/kb-gap.mjs +273 -0
- package/dist/behaviors/kb-hittest.d.mts +34 -0
- package/dist/behaviors/kb-hittest.mjs +409 -0
- package/dist/behaviors/kb-metadata.d.mts +29 -0
- package/dist/behaviors/kb-metadata.mjs +326 -0
- package/dist/behaviors/kb-passage.d.mts +41 -0
- package/dist/behaviors/kb-passage.mjs +529 -0
- package/dist/behaviors/kb-pipeline.d.mts +18 -0
- package/dist/behaviors/kb-pipeline.mjs +381 -0
- package/dist/behaviors/kb-qa.d.mts +26 -0
- package/dist/behaviors/kb-qa.mjs +332 -0
- package/dist/behaviors/kb-rerank.d.mts +20 -0
- package/dist/behaviors/kb-rerank.mjs +315 -0
- package/dist/behaviors/kb-retrieval.d.mts +49 -0
- package/dist/behaviors/kb-retrieval.mjs +746 -0
- package/dist/behaviors/kb-review.d.mts +44 -0
- package/dist/behaviors/kb-review.mjs +451 -0
- package/dist/behaviors/kb-sandbox.d.mts +33 -0
- package/dist/behaviors/kb-sandbox.mjs +325 -0
- package/dist/behaviors/kb-segment.d.mts +32 -0
- package/dist/behaviors/kb-segment.mjs +499 -0
- package/dist/behaviors/kb-sources.d.mts +27 -0
- package/dist/behaviors/kb-sources.mjs +373 -0
- package/dist/behaviors/kb-sql.d.mts +43 -0
- package/dist/behaviors/kb-sql.mjs +948 -0
- package/dist/behaviors/kb-trace.d.mts +16 -0
- package/dist/behaviors/kb-trace.mjs +414 -0
- package/dist/behaviors/kb-visibility.d.mts +44 -0
- package/dist/behaviors/kb-visibility.mjs +403 -0
- package/dist/behaviors/kb-who-can.d.mts +32 -0
- package/dist/behaviors/kb-who-can.mjs +379 -0
- package/dist/behaviors/modal.d.mts +24 -5
- package/dist/behaviors/modal.mjs +76 -10
- package/dist/behaviors/nav.d.mts +1 -1
- package/dist/behaviors/nav.mjs +33 -7
- package/dist/behaviors/notification.d.mts +20 -4
- package/dist/behaviors/notification.mjs +53 -73
- package/dist/behaviors/popover.d.mts +39 -3
- package/dist/behaviors/popover.mjs +90 -4
- package/dist/behaviors/select.d.mts +4 -2
- package/dist/behaviors/select.mjs +161 -24
- package/dist/behaviors/sidebar.d.mts +5 -2
- package/dist/behaviors/sidebar.mjs +43 -13
- package/dist/behaviors/slider.d.mts +5 -2
- package/dist/behaviors/slider.mjs +54 -43
- package/dist/behaviors/split-pane.d.mts +6 -2
- package/dist/behaviors/split-pane.mjs +62 -21
- package/dist/behaviors/tabs.d.mts +3 -2
- package/dist/behaviors/tabs.mjs +65 -14
- package/dist/behaviors/tag-input.d.mts +5 -2
- package/dist/behaviors/tag-input.mjs +61 -21
- package/dist/behaviors/theme.d.mts +13 -2
- package/dist/behaviors/theme.mjs +48 -4
- package/dist/behaviors/toast.d.mts +30 -8
- package/dist/behaviors/toast.mjs +74 -7
- package/dist/behaviors/tree.d.mts +5 -2
- package/dist/behaviors/tree.mjs +38 -15
- package/dist/behaviors/upload.mjs +21 -23
- package/dist/cli.mjs +1 -1
- package/dist/components/ai-branch.mjs +3 -0
- package/dist/components/ai-chat.css +295 -0
- package/dist/components/ai-feedback.mjs +3 -0
- package/dist/components/ai-panel.css +218 -1
- package/dist/components/ai-threads.mjs +3 -0
- package/dist/components/ai-tool-call.mjs +1 -1
- package/dist/components/badge.css +1 -1
- package/dist/components/breadcrumb.css +0 -32
- package/dist/components/chart-calendar.mjs +1 -2
- package/dist/components/chart-graph.css +57 -0
- package/dist/components/chart-graph.mjs +4 -0
- package/dist/components/chart-map.mjs +3 -0
- package/dist/components/chart-pie.css +0 -6
- package/dist/components/chart-scatter.mjs +1 -1
- package/dist/components/charts.css +33 -1
- package/dist/components/charts.mjs +1 -0
- package/dist/components/content.css +3 -16
- package/dist/components/datatable.css +1 -1
- package/dist/components/date-picker.css +1 -1
- package/dist/components/kb-access.mjs +4 -0
- package/dist/components/kb-acl.mjs +4 -0
- package/dist/components/kb-agent.css +481 -0
- package/dist/components/kb-answer.mjs +4 -0
- package/dist/components/kb-audit.mjs +4 -0
- package/dist/components/kb-canvas.mjs +4 -0
- package/dist/components/kb-chain.mjs +4 -0
- package/dist/components/kb-checkpoint.mjs +4 -0
- package/dist/components/kb-chunks.mjs +4 -0
- package/dist/components/kb-citation.mjs +4 -0
- package/dist/components/kb-clarify.mjs +4 -0
- package/dist/components/kb-conflict.mjs +4 -0
- package/dist/components/kb-connector.mjs +4 -0
- package/dist/components/kb-data.css +649 -0
- package/dist/components/kb-eval.mjs +4 -0
- package/dist/components/kb-explain.mjs +4 -0
- package/dist/components/kb-filter.mjs +4 -0
- package/dist/components/kb-gap.mjs +4 -0
- package/dist/components/kb-ground.css +566 -0
- package/dist/components/kb-hittest.mjs +4 -0
- package/dist/components/kb-ingest.css +898 -0
- package/dist/components/kb-metadata.mjs +4 -0
- package/dist/components/kb-ops.css +548 -0
- package/dist/components/kb-passage.mjs +4 -0
- package/dist/components/kb-perm.css +444 -0
- package/dist/components/kb-pipeline.mjs +4 -0
- package/dist/components/kb-qa.mjs +4 -0
- package/dist/components/kb-rerank.mjs +4 -0
- package/dist/components/kb-retrieval.mjs +4 -0
- package/dist/components/kb-review.mjs +4 -0
- package/dist/components/kb-sandbox.mjs +4 -0
- package/dist/components/kb-search.css +940 -0
- package/dist/components/kb-segment.mjs +4 -0
- package/dist/components/kb-sources.mjs +4 -0
- package/dist/components/kb-sql.mjs +4 -0
- package/dist/components/kb-trace.mjs +4 -0
- package/dist/components/kb-visibility.mjs +4 -0
- package/dist/components/kb-who-can.mjs +4 -0
- package/dist/components/kb.css +252 -0
- package/dist/components/kb.mjs +9 -0
- package/dist/components/notification.css +2 -3
- package/dist/components/pagination.css +3 -1
- package/dist/components/pagination.mjs +1 -0
- package/dist/components/rating.mjs +1 -0
- package/dist/components/segmented.css +9 -1
- package/dist/components/segmented.mjs +1 -1
- package/dist/components/select.css +67 -4
- package/dist/components/steps.css +13 -3
- package/dist/components/steps.mjs +1 -0
- package/dist/components/switch.css +3 -1
- package/dist/components/switch.mjs +1 -0
- package/dist/components/table.mjs +1 -0
- package/dist/components/tabs.css +23 -0
- package/dist/components/tag-input.css +1 -6
- package/dist/components/upload.css +0 -15
- package/dist/index.d.mts +48 -11
- package/dist/index.mjs +13205 -3615
- package/dist/registry.json +366 -15
- package/dist/retro-effects.css +3 -16
- package/dist/tokens/retro-effects.css +3 -16
- package/dist/tokens/style-profiles.css +3 -2
- package/dist/tokens/typography.css +2 -0
- package/dist/tokens.css +5 -2
- package/dist/ui.css +5713 -267
- package/docs/research/2026-10-03-ai-kb-components.md +392 -0
- package/docs/research/2026-10-03-kb-permissions.md +992 -0
- package/docs/spec/ai-native.md +7 -4
- package/docs/spec/kb-family.md +443 -0
- package/package.json +2 -2
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// src/behaviors/events.ts
|
|
2
|
+
function onIcen(type, a, b, c) {
|
|
3
|
+
if (typeof document === "undefined") return () => {
|
|
4
|
+
};
|
|
5
|
+
const selector = typeof a === "string" ? a : null;
|
|
6
|
+
const handler = selector ? b : a;
|
|
7
|
+
const opts = selector ? c : b;
|
|
8
|
+
const within = opts?.within ?? document;
|
|
9
|
+
const once = opts?.once === true;
|
|
10
|
+
let off = () => {
|
|
11
|
+
};
|
|
12
|
+
const fn = (e) => {
|
|
13
|
+
const broadcast = !(e.target instanceof Element);
|
|
14
|
+
if (selector) {
|
|
15
|
+
if (broadcast) return;
|
|
16
|
+
const detail = e.detail;
|
|
17
|
+
const src = detail?.source instanceof Element ? detail.source : e.target;
|
|
18
|
+
if (!(src instanceof Element) || !src.closest(selector)) return;
|
|
19
|
+
}
|
|
20
|
+
handler(e);
|
|
21
|
+
if (once) off();
|
|
22
|
+
};
|
|
23
|
+
within.addEventListener(type, fn);
|
|
24
|
+
off = () => {
|
|
25
|
+
within.removeEventListener(type, fn);
|
|
26
|
+
opts?.signal?.removeEventListener("abort", off);
|
|
27
|
+
};
|
|
28
|
+
if (opts?.signal) {
|
|
29
|
+
if (opts.signal.aborted) {
|
|
30
|
+
off();
|
|
31
|
+
return () => {
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
opts.signal.addEventListener("abort", off, { once: true });
|
|
35
|
+
}
|
|
36
|
+
return off;
|
|
37
|
+
}
|
|
38
|
+
function emitIcen(source, type, detail) {
|
|
39
|
+
return source.dispatchEvent(
|
|
40
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
var policies = /* @__PURE__ */ new Map();
|
|
44
|
+
function setEventPolicy(type, policy) {
|
|
45
|
+
if (policy) policies.set(type, policy);
|
|
46
|
+
else policies.delete(type);
|
|
47
|
+
}
|
|
48
|
+
function getEventPolicy(type) {
|
|
49
|
+
return policies.get(type);
|
|
50
|
+
}
|
|
51
|
+
function resetEventPolicies() {
|
|
52
|
+
policies.clear();
|
|
53
|
+
}
|
|
54
|
+
var LONGPRESS_MS = 520;
|
|
55
|
+
var LONGPRESS_MOVE = 12;
|
|
56
|
+
var CLICK_DELAY = 220;
|
|
57
|
+
var CLICK_DRAG_TOLERANCE = 5;
|
|
58
|
+
function gestureHost(e, name) {
|
|
59
|
+
const t = e.target;
|
|
60
|
+
if (!(t instanceof Element)) return null;
|
|
61
|
+
return t.closest(`[data-gestures~="${name}"]`);
|
|
62
|
+
}
|
|
63
|
+
function pointOf(e) {
|
|
64
|
+
return e instanceof MouseEvent || typeof PointerEvent !== "undefined" && e instanceof PointerEvent ? { x: e.clientX, y: e.clientY } : { x: 0, y: 0 };
|
|
65
|
+
}
|
|
66
|
+
function emit(host, type, originalEvent, text) {
|
|
67
|
+
const { x, y } = pointOf(originalEvent);
|
|
68
|
+
const detail = { source: host, originalEvent, x, y };
|
|
69
|
+
if (text != null) detail.text = text;
|
|
70
|
+
const ev = new CustomEvent(type, {
|
|
71
|
+
detail,
|
|
72
|
+
bubbles: true,
|
|
73
|
+
composed: true,
|
|
74
|
+
cancelable: true
|
|
75
|
+
});
|
|
76
|
+
const delivered = host.dispatchEvent(ev);
|
|
77
|
+
if (delivered) policies.get(type)?.(ev);
|
|
78
|
+
return ev;
|
|
79
|
+
}
|
|
80
|
+
var gesturesInit = false;
|
|
81
|
+
var gesturesTeardown = null;
|
|
82
|
+
function initGestures() {
|
|
83
|
+
if (gesturesInit || typeof document === "undefined") return () => {
|
|
84
|
+
};
|
|
85
|
+
gesturesInit = true;
|
|
86
|
+
let clickTimer = null;
|
|
87
|
+
let pending = null;
|
|
88
|
+
let downPos = null;
|
|
89
|
+
let suppressTrailingClick = false;
|
|
90
|
+
const cancelPendingClick = () => {
|
|
91
|
+
if (clickTimer) clearTimeout(clickTimer);
|
|
92
|
+
clickTimer = null;
|
|
93
|
+
pending = null;
|
|
94
|
+
};
|
|
95
|
+
const onDownPos = (e) => {
|
|
96
|
+
downPos = { x: e.clientX, y: e.clientY };
|
|
97
|
+
suppressTrailingClick = false;
|
|
98
|
+
};
|
|
99
|
+
const isDragRelease = (e) => downPos != null && Math.hypot(e.clientX - downPos.x, e.clientY - downPos.y) > CLICK_DRAG_TOLERANCE;
|
|
100
|
+
const onClick = (e) => {
|
|
101
|
+
const host = gestureHost(e, "click");
|
|
102
|
+
if (!host) return;
|
|
103
|
+
if (suppressTrailingClick) {
|
|
104
|
+
suppressTrailingClick = false;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (isDragRelease(e)) return;
|
|
108
|
+
if (host.matches('[data-gestures~="dblclick"]')) {
|
|
109
|
+
if (clickTimer) clearTimeout(clickTimer);
|
|
110
|
+
pending = { host, e };
|
|
111
|
+
clickTimer = setTimeout(() => {
|
|
112
|
+
clickTimer = null;
|
|
113
|
+
const p = pending;
|
|
114
|
+
pending = null;
|
|
115
|
+
if (p) emit(p.host, "icen:click", p.e);
|
|
116
|
+
}, CLICK_DELAY);
|
|
117
|
+
} else {
|
|
118
|
+
emit(host, "icen:click", e);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const onDblClick = (e) => {
|
|
122
|
+
const host = gestureHost(e, "dblclick");
|
|
123
|
+
if (!host) return;
|
|
124
|
+
cancelPendingClick();
|
|
125
|
+
if (isDragRelease(e)) return;
|
|
126
|
+
emit(host, "icen:dblclick", e);
|
|
127
|
+
};
|
|
128
|
+
const onContextMenu = (e) => {
|
|
129
|
+
const host = gestureHost(e, "contextmenu");
|
|
130
|
+
if (!host) return;
|
|
131
|
+
const hasPolicy = policies.has("icen:contextmenu");
|
|
132
|
+
const ev = emit(host, "icen:contextmenu", e);
|
|
133
|
+
if (ev.defaultPrevented || hasPolicy) e.preventDefault();
|
|
134
|
+
};
|
|
135
|
+
let lp = null;
|
|
136
|
+
const clearLp = () => {
|
|
137
|
+
if (lp) clearTimeout(lp.timer);
|
|
138
|
+
lp = null;
|
|
139
|
+
};
|
|
140
|
+
const onLpDown = (e) => {
|
|
141
|
+
const host = gestureHost(e, "longpress");
|
|
142
|
+
if (!host) return;
|
|
143
|
+
clearLp();
|
|
144
|
+
lp = {
|
|
145
|
+
host,
|
|
146
|
+
e,
|
|
147
|
+
x: e.clientX,
|
|
148
|
+
y: e.clientY,
|
|
149
|
+
timer: setTimeout(() => {
|
|
150
|
+
const cur = lp;
|
|
151
|
+
lp = null;
|
|
152
|
+
if (cur) {
|
|
153
|
+
suppressTrailingClick = true;
|
|
154
|
+
emit(cur.host, "icen:longpress", cur.e);
|
|
155
|
+
}
|
|
156
|
+
}, LONGPRESS_MS)
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
const onLpMove = (e) => {
|
|
160
|
+
if (!lp) return;
|
|
161
|
+
if (Math.hypot(e.clientX - lp.x, e.clientY - lp.y) > LONGPRESS_MOVE) clearLp();
|
|
162
|
+
};
|
|
163
|
+
const onTextSelect = (e) => {
|
|
164
|
+
const host = gestureHost(e, "text-select");
|
|
165
|
+
if (!host) return;
|
|
166
|
+
const sel = window.getSelection();
|
|
167
|
+
const text = sel?.toString() ?? "";
|
|
168
|
+
if (!text.trim() || !sel || !host.contains(sel.anchorNode)) return;
|
|
169
|
+
emit(host, "icen:text-select", e, text);
|
|
170
|
+
};
|
|
171
|
+
document.addEventListener("pointerdown", onDownPos);
|
|
172
|
+
document.addEventListener("click", onClick);
|
|
173
|
+
document.addEventListener("dblclick", onDblClick);
|
|
174
|
+
document.addEventListener("contextmenu", onContextMenu);
|
|
175
|
+
document.addEventListener("pointerdown", onLpDown);
|
|
176
|
+
document.addEventListener("pointermove", onLpMove);
|
|
177
|
+
document.addEventListener("pointerup", clearLp);
|
|
178
|
+
document.addEventListener("pointercancel", clearLp);
|
|
179
|
+
document.addEventListener("mouseup", onTextSelect);
|
|
180
|
+
gesturesTeardown = () => {
|
|
181
|
+
document.removeEventListener("pointerdown", onDownPos);
|
|
182
|
+
document.removeEventListener("click", onClick);
|
|
183
|
+
document.removeEventListener("dblclick", onDblClick);
|
|
184
|
+
document.removeEventListener("contextmenu", onContextMenu);
|
|
185
|
+
document.removeEventListener("pointerdown", onLpDown);
|
|
186
|
+
document.removeEventListener("pointermove", onLpMove);
|
|
187
|
+
document.removeEventListener("pointerup", clearLp);
|
|
188
|
+
document.removeEventListener("pointercancel", clearLp);
|
|
189
|
+
document.removeEventListener("mouseup", onTextSelect);
|
|
190
|
+
cancelPendingClick();
|
|
191
|
+
clearLp();
|
|
192
|
+
gesturesInit = false;
|
|
193
|
+
gesturesTeardown = null;
|
|
194
|
+
};
|
|
195
|
+
return gesturesTeardown;
|
|
196
|
+
}
|
|
197
|
+
function destroyGestures() {
|
|
198
|
+
gesturesTeardown?.();
|
|
199
|
+
}
|
|
200
|
+
export {
|
|
201
|
+
destroyGestures,
|
|
202
|
+
emitIcen,
|
|
203
|
+
getEventPolicy,
|
|
204
|
+
initGestures,
|
|
205
|
+
onIcen,
|
|
206
|
+
resetEventPolicies,
|
|
207
|
+
setEventPolicy
|
|
208
|
+
};
|
package/dist/behaviors/input.mjs
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
// src/behaviors/events.ts
|
|
2
|
+
function emitIcen(source, type, detail) {
|
|
3
|
+
return source.dispatchEvent(
|
|
4
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
5
|
+
);
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
// src/behaviors/input.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
9
|
+
function trackComposing(target) {
|
|
10
|
+
let composing = false;
|
|
11
|
+
target.addEventListener("compositionstart", () => {
|
|
12
|
+
composing = true;
|
|
6
13
|
});
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
target.addEventListener("compositionend", () => {
|
|
15
|
+
composing = false;
|
|
9
16
|
});
|
|
17
|
+
return () => composing;
|
|
10
18
|
}
|
|
11
19
|
function setupClear(wrap) {
|
|
12
20
|
const btn = wrap.querySelector(".input-clear");
|
|
@@ -58,7 +66,6 @@ function setupCounter(field) {
|
|
|
58
66
|
const maxAttr = field.getAttribute("maxlength");
|
|
59
67
|
const dataCount = field.getAttribute("data-count");
|
|
60
68
|
if (!maxAttr && dataCount === null) return;
|
|
61
|
-
el.__icenCounterInit = true;
|
|
62
69
|
const max = maxAttr ? Number(maxAttr) : 0;
|
|
63
70
|
let counter = null;
|
|
64
71
|
const wrap = field.closest(".input-wrap, .textarea-wrap");
|
|
@@ -75,6 +82,8 @@ function setupCounter(field) {
|
|
|
75
82
|
}
|
|
76
83
|
const counterEl = counter;
|
|
77
84
|
if (!counterEl) return;
|
|
85
|
+
el.__icenCounterInit = true;
|
|
86
|
+
const isComposing = trackComposing(field);
|
|
78
87
|
function update() {
|
|
79
88
|
const len = field.value.length;
|
|
80
89
|
counterEl.textContent = max > 0 ? `${len} / ${max}` : `${len}`;
|
|
@@ -85,8 +94,9 @@ function setupCounter(field) {
|
|
|
85
94
|
else if (ratio >= 0.8) counterEl.classList.add("is-warn");
|
|
86
95
|
}
|
|
87
96
|
}
|
|
97
|
+
;
|
|
88
98
|
field.addEventListener("input", () => {
|
|
89
|
-
if (!isComposing) update();
|
|
99
|
+
if (!isComposing()) update();
|
|
90
100
|
});
|
|
91
101
|
update();
|
|
92
102
|
}
|
|
@@ -96,6 +106,7 @@ function setupMask(field) {
|
|
|
96
106
|
const mask = field.getAttribute("data-mask");
|
|
97
107
|
if (!mask) return;
|
|
98
108
|
el.__icenMaskInit = true;
|
|
109
|
+
const isComposing = trackComposing(field);
|
|
99
110
|
const maskChars = [];
|
|
100
111
|
for (const ch of mask) maskChars.push(ch);
|
|
101
112
|
function isInputSlot(ch) {
|
|
@@ -137,7 +148,7 @@ function setupMask(field) {
|
|
|
137
148
|
field.value = lastFormatted;
|
|
138
149
|
field.setAttribute("data-raw-value", extractRaw(lastFormatted));
|
|
139
150
|
field.addEventListener("input", () => {
|
|
140
|
-
if (isComposing) return;
|
|
151
|
+
if (isComposing()) return;
|
|
141
152
|
const cursorPos = field.selectionStart ?? 0;
|
|
142
153
|
const oldRaw = extractRaw(lastFormatted);
|
|
143
154
|
const newFull = field.value;
|
|
@@ -165,7 +176,7 @@ function setupMask(field) {
|
|
|
165
176
|
field.setSelectionRange(targetCursor, targetCursor);
|
|
166
177
|
});
|
|
167
178
|
field.addEventListener("keydown", (ev) => {
|
|
168
|
-
if (isComposing) return;
|
|
179
|
+
if (isComposing()) return;
|
|
169
180
|
if (ev.ctrlKey || ev.metaKey || ev.altKey) return;
|
|
170
181
|
if (["Backspace", "Delete", "Tab", "Escape", "ArrowLeft", "ArrowRight", "Home", "End", "Enter"].includes(ev.key)) return;
|
|
171
182
|
const currentRaw = extractRaw(field.value);
|
|
@@ -195,6 +206,7 @@ function setupOtp(group) {
|
|
|
195
206
|
const el = group;
|
|
196
207
|
if (el.__icenInputInit) return;
|
|
197
208
|
el.__icenInputInit = true;
|
|
209
|
+
const isComposing = trackComposing(group);
|
|
198
210
|
const cells = Array.from(group.querySelectorAll(".otp-cell"));
|
|
199
211
|
const syncFilled = (cell) => {
|
|
200
212
|
cell.classList.toggle("is-filled", cell.value.length > 0);
|
|
@@ -205,7 +217,7 @@ function setupOtp(group) {
|
|
|
205
217
|
}
|
|
206
218
|
syncFilled(cell);
|
|
207
219
|
cell.addEventListener("input", () => {
|
|
208
|
-
if (isComposing) return;
|
|
220
|
+
if (isComposing()) return;
|
|
209
221
|
const ch = cell.value.slice(-1);
|
|
210
222
|
cell.value = ch;
|
|
211
223
|
syncFilled(cell);
|
|
@@ -239,7 +251,8 @@ function setupOtp(group) {
|
|
|
239
251
|
const fireComplete = () => {
|
|
240
252
|
const code = cells.map((c) => c.value).join("");
|
|
241
253
|
if (code.length === cells.length && cells.every((c) => c.value.length > 0)) {
|
|
242
|
-
group.
|
|
254
|
+
group.classList.add("is-complete");
|
|
255
|
+
emitIcen(group, "icen:otp-complete", { code });
|
|
243
256
|
group.dispatchEvent(new CustomEvent("otp:complete", { detail: { code }, bubbles: true }));
|
|
244
257
|
}
|
|
245
258
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { KbAccessRequest, KbAccessState, KbRole } from './kb-core.js';
|
|
2
|
+
import './ai-core.js';
|
|
3
|
+
|
|
4
|
+
/** createKbAccess 入参(spec §9.3;request 宽进——素对象经 normalizeAccessRequest 归一) */
|
|
5
|
+
interface KbAccessOpts {
|
|
6
|
+
/** 当前访问请求(内部持有副本,不打脏调用方数据) */
|
|
7
|
+
request: KbAccessRequest | Record<string, unknown>;
|
|
8
|
+
/** requester = 申请人视角(被拒五件套 + 表单);approver = 审批人视角(队列卡)。缺省 requester */
|
|
9
|
+
mode?: 'requester' | 'approver';
|
|
10
|
+
/** 表单提交回调(与 icen:kb-access-request 双通道) */
|
|
11
|
+
onRequest?: (r: KbAccessRequest) => void;
|
|
12
|
+
/** 审批决定回调(与 icen:kb-access-decide 双通道;approve 时 role = 批准档位) */
|
|
13
|
+
onDecide?: (id: string, decision: 'approve' | 'deny', role?: KbRole) => void;
|
|
14
|
+
/** 被拒原因文案(缺省固定模板「此内容仅对授权者开放」——不给受限侧任何更多信息,§9.0.3) */
|
|
15
|
+
deniedHint?: string;
|
|
16
|
+
/** 切换身份回调(宿主关注:切换固定身份集重查权限;不派库事件) */
|
|
17
|
+
onSwitchIdentity?: () => void;
|
|
18
|
+
}
|
|
19
|
+
/** createKbAccess 句柄(函数名冻结于 spec §9.3) */
|
|
20
|
+
interface KbAccessHandle {
|
|
21
|
+
/** 合并更新请求字段(Partial)或整体切状态(单字符串);带过期时间的 granted 会即时派生 expired */
|
|
22
|
+
setState(next: Partial<KbAccessRequest> | KbAccessState): void;
|
|
23
|
+
/** 当前请求(normalize 后的副本;外部修改不影响内部) */
|
|
24
|
+
getState(): KbAccessRequest;
|
|
25
|
+
/** 清空 DOM 与标记(幂等;同一 el 重复 create 会先销毁旧实例) */
|
|
26
|
+
destroy(): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 创建访问申请流(requester:被拒五件套 + 表单 + 状态徽章族;approver:审批队列卡)。
|
|
30
|
+
* 快照渲染:setState / 表单交互后整树重建(重建前回填用户已输入的理由/时长,不打断打字)。
|
|
31
|
+
*/
|
|
32
|
+
declare function createKbAccess(el: HTMLElement, opts: KbAccessOpts): KbAccessHandle;
|
|
33
|
+
|
|
34
|
+
export { type KbAccessHandle, type KbAccessOpts, createKbAccess };
|