@lostgradient/cinder 0.7.0 → 0.8.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/CHANGELOG.md +14 -0
- package/README.md +5 -0
- package/components.json +1 -1
- package/dist/components/chat/chat.schema.js +6 -1
- package/dist/components/chat/chat.svelte.d.ts +2 -0
- package/dist/components/chat/chat.types.d.ts +6 -0
- package/dist/components/chat/container/chat.svelte.d.ts +2 -0
- package/dist/components/chat/index.d.ts +1 -1
- package/dist/components/chat/index.js +33 -5
- package/dist/components/chat/input/chat-input.svelte.d.ts +3 -0
- package/dist/components/navigation-bar/index.js +44 -6
- package/dist/components/sidebar/index.js +6 -3
- package/dist/components/sidebar/sidebar.css +4 -0
- package/dist/index.js +81 -12
- package/dist/server/components/chat/index.js +1 -1
- package/dist/server/components/navigation-bar/index.js +1 -1
- package/dist/server/components/sidebar/index.js +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/{index.server-zeqv7nrz.js → index.server-5tf22d6e.js} +43 -6
- package/dist/server/{index.server-qwknp759.js → index.server-69epaape.js} +6 -3
- package/dist/server/{index.server-bvmwnjx6.js → index.server-v4zabrsx.js} +28 -3
- package/package.json +3 -1
- package/src/components/chat/chat.schema.json +5 -0
- package/src/components/chat/chat.schema.ts +6 -0
- package/src/components/chat/chat.svelte +8 -0
- package/src/components/chat/chat.types.ts +6 -0
- package/src/components/chat/container/chat.svelte +10 -1
- package/src/components/chat/index.ts +1 -1
- package/src/components/chat/input/chat-input.svelte +11 -1
- package/src/components/navigation-bar/navigation-bar.svelte +49 -7
- package/src/components/sidebar/sidebar.css +4 -0
- package/src/components/sidebar/sidebar.svelte +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @lostgradient/cinder
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`9686390`](https://github.com/stevekinney/cinder/commit/9686390483ce91eebe82f2f28852e436c1f2724a) Thanks [@stevekinney](https://github.com/stevekinney)! - `Chat` composer public API: added `clearInput()`, `getComposerValue()`, and an `oncomposerinput` callback prop so consumers can read, clear, and observe the composer's plain-text value without reaching into `.chat-input-editor` DOM directly (useful for building slash-command, mention, or autocomplete UX layered on top of the composer).
|
|
8
|
+
|
|
9
|
+
Also re-exported the `ChatAttachment` type from the public `@lostgradient/cinder/chat` entry — previously consumers had to derive it from `ChatSubmitEvent['attachments'][number]`.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#675](https://github.com/stevekinney/cinder/pull/675) [`e55561d`](https://github.com/stevekinney/cinder/commit/e55561db6d348573e29df711c095b2ec18e197ef) Thanks [@stevekinney](https://github.com/stevekinney)! - Close a collapsed top NavigationBar mobile menu after enabled item activation.
|
|
14
|
+
|
|
15
|
+
- [#667](https://github.com/stevekinney/cinder/pull/667) [`d9ce2c3`](https://github.com/stevekinney/cinder/commit/d9ce2c3660805d8b6a7e964f3f671174c61ca819) Thanks [@stevekinney](https://github.com/stevekinney)! - Internal build and validation overhaul: content-hash build caching (with the cache marker excluded from the published tarball), global test cleanup registration, and a lint script split into `lint` and `lint:invariants`.
|
|
16
|
+
|
|
3
17
|
## 0.7.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -18,6 +18,11 @@ Rich editor, markdown rendering, editor/commentary re-exports, and syntax-highli
|
|
|
18
18
|
bun add @milkdown/ctx @milkdown/kit @milkdown/prose @shikijs/engine-oniguruma @shikijs/langs @shikijs/rehype @shikijs/types @types/hast @types/mdast @types/unist comlink hast-util-sanitize js-yaml prosemirror-inputrules prosemirror-model prosemirror-state prosemirror-view rehype-katex rehype-sanitize rehype-stringify remark-gfm remark-html remark-math remark-parse remark-rehype remark-stringify shiki unified unist-util-remove unist-util-visit
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
`@lostgradient/cinder/markdown-editor` needs the editor and Markdown pipeline subset from that
|
|
22
|
+
list at build time. If `prosemirror-state`, `prosemirror-view`, `@milkdown/kit`, or another editor
|
|
23
|
+
peer is missing, Vite may report the failure through its optional-peer placeholder module instead
|
|
24
|
+
of naming this install step.
|
|
25
|
+
|
|
21
26
|
## Quickstart
|
|
22
27
|
|
|
23
28
|
Load the base stylesheet once at your app entry:
|
package/components.json
CHANGED
|
@@ -225,6 +225,11 @@ generation. When an adapter is also wired, Chat calls
|
|
|
225
225
|
name: "onattachmentremove",
|
|
226
226
|
reason: "function-or-snippet"
|
|
227
227
|
},
|
|
228
|
+
{
|
|
229
|
+
name: "oncomposerinput",
|
|
230
|
+
reason: "function-or-snippet",
|
|
231
|
+
description: "Called with the composer's current plain-text value on every composer\ninput event. Lets a consumer build slash-command, mention, or autocomplete\nUX without reaching into `.chat-input-editor` DOM directly."
|
|
232
|
+
},
|
|
228
233
|
{
|
|
229
234
|
name: "ondeny",
|
|
230
235
|
reason: "function-or-snippet",
|
|
@@ -316,4 +321,4 @@ export {
|
|
|
316
321
|
chat_schema_default as default
|
|
317
322
|
};
|
|
318
323
|
|
|
319
|
-
//# debugId=
|
|
324
|
+
//# debugId=9906999F3FA9B93664756E2164756E21
|
|
@@ -21,6 +21,8 @@ declare const Chat: import("svelte").Component<ChatProps, {
|
|
|
21
21
|
scrollToBottom: () => void;
|
|
22
22
|
scrollToTop: () => void;
|
|
23
23
|
focusInput: () => void;
|
|
24
|
+
clearInput: () => void;
|
|
25
|
+
getComposerValue: () => string;
|
|
24
26
|
}, "">;
|
|
25
27
|
type Chat = ReturnType<typeof Chat>;
|
|
26
28
|
export default Chat;
|
|
@@ -228,4 +228,10 @@ export type ChatProps = Omit<HTMLAttributes<HTMLElement>, 'class' | 'onsubmit'>
|
|
|
228
228
|
onattachmentadd?: (attachment: ChatAttachment) => void;
|
|
229
229
|
onattachmentremove?: (attachment: ChatAttachment) => void;
|
|
230
230
|
onattachmentfailure?: (file: File, error: string) => void;
|
|
231
|
+
/**
|
|
232
|
+
* Called with the composer's current plain-text value on every composer
|
|
233
|
+
* input event. Lets a consumer build slash-command, mention, or autocomplete
|
|
234
|
+
* UX without reaching into `.chat-input-editor` DOM directly.
|
|
235
|
+
*/
|
|
236
|
+
oncomposerinput?: (value: string) => void;
|
|
231
237
|
};
|
|
@@ -5,6 +5,8 @@ declare const Chat: import("svelte").Component<ChatProps, {
|
|
|
5
5
|
scrollToBottom: () => void;
|
|
6
6
|
scrollToTop: () => void;
|
|
7
7
|
focusInput: () => void;
|
|
8
|
+
clearInput: () => void;
|
|
9
|
+
getComposerValue: () => string;
|
|
8
10
|
beginStreaming: (messageId: string) => void;
|
|
9
11
|
pushToken: (token: string) => void;
|
|
10
12
|
endStreaming: () => void;
|
|
@@ -15,7 +15,7 @@ export { appendAssistantMessage, appendMessages, appendUserMessage, createConver
|
|
|
15
15
|
export type { AssistantMessage, ContainerUploadContent, ConversationHistory, ConversationStatus, ExportOptions, ImageContent, JSONValue, Message, MessageInput, MessageRole, MultiModalContent, RedactedThinkingContent, ServerToolResultContent, ServerToolResultType, ServerToolUseContent, TextContent, ThinkingContent, ToMarkdownOptions, TokenUsage, ToolAction, ToolCall, ToolCallPair, ToolError, ToolErrorCategory, ToolResult, WebSearchToolResultContent, } from './conversation-model.ts';
|
|
16
16
|
export { formatMessageAsMarkdown, getMessageRoleLabel, getMessageText, messagesToMarkdown, type ChatExportOptions, type DeliveryStatus, } from './utilities';
|
|
17
17
|
export { ChatAttachmentPreview, ChatInput, deriveAttachmentKind } from './input';
|
|
18
|
-
export type { AttachmentKind } from './input';
|
|
18
|
+
export type { AttachmentKind, ChatAttachment } from './input';
|
|
19
19
|
export { ChatDateSeparator, ChatMessage, MessageAttachments, MessageContent, ToolCallGroup, } from './message';
|
|
20
20
|
export { DEFAULT_SCROLL_CONFIGURATION, calculateScrollToBottom, calculateUnreadCount, extractTimestamp, findUnreadBoundaryIndex, isAtBottom, shouldShowJumpToLatest, } from './container';
|
|
21
21
|
export type { ChatScrollStateChangeEvent, ChatStopGeneratingEvent, ChatSubmitEvent, ChatUnreadIndicatorChangeEvent, ScrollConfiguration, ScrollState, } from './container';
|
|
@@ -10003,6 +10003,7 @@ var rest_excludes11 = new Set([
|
|
|
10003
10003
|
"acceptedTypes",
|
|
10004
10004
|
"onsubmit",
|
|
10005
10005
|
"onstop",
|
|
10006
|
+
"oncomposerinput",
|
|
10006
10007
|
"onattachmentadd",
|
|
10007
10008
|
"onattachmentremove",
|
|
10008
10009
|
"onattachmentfailure",
|
|
@@ -10202,6 +10203,9 @@ function Chat_input($$anchor, $$props) {
|
|
|
10202
10203
|
function handleCompositionEnd() {
|
|
10203
10204
|
$45.set(isComposing, false);
|
|
10204
10205
|
}
|
|
10206
|
+
function handleInput() {
|
|
10207
|
+
$$props.oncomposerinput?.(value());
|
|
10208
|
+
}
|
|
10205
10209
|
function focus() {
|
|
10206
10210
|
$45.get(editorElement)?.focus();
|
|
10207
10211
|
}
|
|
@@ -10213,6 +10217,9 @@ function Chat_input($$anchor, $$props) {
|
|
|
10213
10217
|
function getAttachments() {
|
|
10214
10218
|
return [...$45.get(attachments)];
|
|
10215
10219
|
}
|
|
10220
|
+
function getValue() {
|
|
10221
|
+
return value();
|
|
10222
|
+
}
|
|
10216
10223
|
function addFiles(files) {
|
|
10217
10224
|
if (!allowAttachments())
|
|
10218
10225
|
return;
|
|
@@ -10221,7 +10228,7 @@ function Chat_input($$anchor, $$props) {
|
|
|
10221
10228
|
onDestroy(() => {
|
|
10222
10229
|
$45.get(attachments).forEach((a) => URL.revokeObjectURL(a.previewUrl));
|
|
10223
10230
|
});
|
|
10224
|
-
var $$exports = { focus, clear, getAttachments, addFiles };
|
|
10231
|
+
var $$exports = { focus, clear, getAttachments, getValue, addFiles };
|
|
10225
10232
|
var form = root_9();
|
|
10226
10233
|
$45.attribute_effect(form, ($0) => ({
|
|
10227
10234
|
class: $0,
|
|
@@ -10456,11 +10463,12 @@ function Chat_input($$anchor, $$props) {
|
|
|
10456
10463
|
$45.set_attribute(span, "id", $45.get(shortcutDescriptionId));
|
|
10457
10464
|
$45.set_text(text_4, announcer.message);
|
|
10458
10465
|
});
|
|
10466
|
+
$45.delegated("input", textarea, handleInput);
|
|
10459
10467
|
$45.bind_value(textarea, value);
|
|
10460
10468
|
$45.append($$anchor, form);
|
|
10461
10469
|
return $45.pop($$exports);
|
|
10462
10470
|
}
|
|
10463
|
-
$45.delegate(["click", "change"]);
|
|
10471
|
+
$45.delegate(["click", "input", "change"]);
|
|
10464
10472
|
// src/components/chat/container/scroll-utilities.ts
|
|
10465
10473
|
var DEFAULT_SCROLL_CONFIGURATION = {
|
|
10466
10474
|
bottomThreshold: 150,
|
|
@@ -11898,7 +11906,8 @@ var rest_excludes12 = new Set([
|
|
|
11898
11906
|
"onexpandedchange",
|
|
11899
11907
|
"onattachmentadd",
|
|
11900
11908
|
"onattachmentremove",
|
|
11901
|
-
"onattachmentfailure"
|
|
11909
|
+
"onattachmentfailure",
|
|
11910
|
+
"oncomposerinput"
|
|
11902
11911
|
]);
|
|
11903
11912
|
var root30 = $65.from_html(`<span class="chat-typing-status svelte-932akd"> </span>`);
|
|
11904
11913
|
var root_121 = $65.from_html(`<span class="chat-typing-dot svelte-932akd" aria-hidden="true"></span> <span class="chat-typing-dot svelte-932akd" aria-hidden="true"></span> <span class="chat-typing-dot svelte-932akd" aria-hidden="true"></span>`, 1);
|
|
@@ -12674,6 +12683,12 @@ function Chat($$anchor, $$props) {
|
|
|
12674
12683
|
function focusInput() {
|
|
12675
12684
|
inputRef?.focus();
|
|
12676
12685
|
}
|
|
12686
|
+
function clearInput() {
|
|
12687
|
+
inputRef?.clear();
|
|
12688
|
+
}
|
|
12689
|
+
function getComposerValue() {
|
|
12690
|
+
return inputRef?.getValue() ?? "";
|
|
12691
|
+
}
|
|
12677
12692
|
function beginStreaming(messageId) {
|
|
12678
12693
|
if (streamingScrollRaf !== undefined) {
|
|
12679
12694
|
cancelAnimationFrame(streamingScrollRaf);
|
|
@@ -12739,6 +12754,8 @@ function Chat($$anchor, $$props) {
|
|
|
12739
12754
|
scrollToBottom,
|
|
12740
12755
|
scrollToTop,
|
|
12741
12756
|
focusInput,
|
|
12757
|
+
clearInput,
|
|
12758
|
+
getComposerValue,
|
|
12742
12759
|
beginStreaming,
|
|
12743
12760
|
pushToken,
|
|
12744
12761
|
endStreaming
|
|
@@ -13210,6 +13227,9 @@ function Chat($$anchor, $$props) {
|
|
|
13210
13227
|
get onstop() {
|
|
13211
13228
|
return $65.get($0);
|
|
13212
13229
|
},
|
|
13230
|
+
get oncomposerinput() {
|
|
13231
|
+
return $$props.oncomposerinput;
|
|
13232
|
+
},
|
|
13213
13233
|
get onattachmentadd() {
|
|
13214
13234
|
return $$props.onattachmentadd;
|
|
13215
13235
|
},
|
|
@@ -13278,13 +13298,21 @@ function Chat2($$anchor, $$props) {
|
|
|
13278
13298
|
function focusInput() {
|
|
13279
13299
|
impl?.focusInput();
|
|
13280
13300
|
}
|
|
13301
|
+
function clearInput() {
|
|
13302
|
+
impl?.clearInput();
|
|
13303
|
+
}
|
|
13304
|
+
function getComposerValue() {
|
|
13305
|
+
return impl?.getComposerValue() ?? "";
|
|
13306
|
+
}
|
|
13281
13307
|
var $$exports = {
|
|
13282
13308
|
beginStreaming,
|
|
13283
13309
|
pushToken,
|
|
13284
13310
|
endStreaming,
|
|
13285
13311
|
scrollToBottom,
|
|
13286
13312
|
scrollToTop,
|
|
13287
|
-
focusInput
|
|
13313
|
+
focusInput,
|
|
13314
|
+
clearInput,
|
|
13315
|
+
getComposerValue
|
|
13288
13316
|
};
|
|
13289
13317
|
$66.bind_this(Chat($$anchor, $66.spread_props({
|
|
13290
13318
|
get class() {
|
|
@@ -14785,4 +14813,4 @@ export {
|
|
|
14785
14813
|
Artifact_panel as ArtifactPanel
|
|
14786
14814
|
};
|
|
14787
14815
|
|
|
14788
|
-
//# debugId=
|
|
14816
|
+
//# debugId=A92B5858E013516164756E2164756E21
|
|
@@ -36,6 +36,8 @@ export type ChatInputProps = Omit<HTMLFormAttributes, 'onsubmit' | 'class'> & {
|
|
|
36
36
|
onsubmit?: (message: MessageInput, attachments: ChatAttachment[]) => void;
|
|
37
37
|
/** Called when stop is requested (transforms send button into stop button when sending=true) */
|
|
38
38
|
onstop?: (() => void) | undefined;
|
|
39
|
+
/** Called with the composer's current plain-text value on every input event. */
|
|
40
|
+
oncomposerinput?: ((value: string) => void) | undefined;
|
|
39
41
|
/** Called when an attachment is added */
|
|
40
42
|
onattachmentadd?: ((attachment: ChatAttachment) => void) | undefined;
|
|
41
43
|
/** Called when an attachment is removed */
|
|
@@ -49,6 +51,7 @@ declare const ChatInput: import("svelte").Component<ChatInputProps, {
|
|
|
49
51
|
focus: () => void;
|
|
50
52
|
clear: () => void;
|
|
51
53
|
getAttachments: () => ChatAttachment[];
|
|
54
|
+
getValue: () => string;
|
|
52
55
|
addFiles: (files: File[]) => void;
|
|
53
56
|
}, "value">;
|
|
54
57
|
type ChatInput = ReturnType<typeof ChatInput>;
|
|
@@ -85,6 +85,7 @@ var rest_excludes = new Set([
|
|
|
85
85
|
"data-cinder-placement",
|
|
86
86
|
"data-cinder-label-visibility",
|
|
87
87
|
"data-cinder-menu-toggle-placement",
|
|
88
|
+
"onclick",
|
|
88
89
|
"onkeydown"
|
|
89
90
|
]);
|
|
90
91
|
var root = $.from_html(`<div class="cinder-navigation-bar__menu-toggle"><!></div>`);
|
|
@@ -98,6 +99,7 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
98
99
|
const FALLBACK_ROOT_FONT_SIZE_PX = 16;
|
|
99
100
|
let placement = $.prop($$props, "placement", 3, "top"), showLabels = $.prop($$props, "showLabels", 3, "always"), menuTogglePlacement = $.prop($$props, "menuTogglePlacement", 3, "after-brand"), mobileMenuOpen = $.prop($$props, "mobileMenuOpen", 15, false), label = $.prop($$props, "label", 3, "Main navigation"), rest = $.rest_props($$props, rest_excludes);
|
|
100
101
|
const navigationItemSelector = "[data-cinder-navigation-item]";
|
|
102
|
+
const toggleFocusSelector = '.cinder-navigation-bar__menu-toggle button, .cinder-navigation-bar__menu-toggle [href], .cinder-navigation-bar__menu-toggle input, .cinder-navigation-bar__menu-toggle select, .cinder-navigation-bar__menu-toggle textarea, .cinder-navigation-bar__menu-toggle [tabindex]:not([tabindex="-1"])';
|
|
101
103
|
const isCollapsible = $.derived(() => placement() === "top" && $$props.menuToggle !== undefined);
|
|
102
104
|
let isMobileLayout = $.state(false);
|
|
103
105
|
const variant = $.derived(() => placement() === "bottom" ? "mobile" : $.get(isCollapsible) && $.get(isMobileLayout) && mobileMenuOpen() ? "mobile" : "horizontal");
|
|
@@ -170,15 +172,50 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
170
172
|
return item.getAttribute("aria-disabled") !== "true" && !item.hasAttribute("disabled");
|
|
171
173
|
}
|
|
172
174
|
function getEventNavigationItem(event) {
|
|
173
|
-
if (!(event.target instanceof
|
|
175
|
+
if (!(event.target instanceof Element) || !itemsRegionElement)
|
|
174
176
|
return null;
|
|
175
177
|
const navigationItem = event.target.closest(navigationItemSelector);
|
|
176
178
|
if (!navigationItem || !itemsRegionElement.contains(navigationItem))
|
|
177
179
|
return null;
|
|
178
|
-
if (navigationItem !== event.target)
|
|
179
|
-
return null;
|
|
180
180
|
return navigationItem;
|
|
181
181
|
}
|
|
182
|
+
function isModifiedClick(event) {
|
|
183
|
+
return event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
184
|
+
}
|
|
185
|
+
function opensOutsideCurrentPage(item) {
|
|
186
|
+
if (!(item instanceof HTMLAnchorElement))
|
|
187
|
+
return false;
|
|
188
|
+
const target = item.getAttribute("target");
|
|
189
|
+
return item.hasAttribute("download") || target !== null && target.trim() !== "" && target.trim().toLowerCase() !== "_self";
|
|
190
|
+
}
|
|
191
|
+
function canCloseAfterItemActivation(item, event) {
|
|
192
|
+
return $.get(isCollapsible) && $.get(isMobileLayout) && mobileMenuOpen() && isEnabledNavigationItem(item) && !isModifiedClick(event) && !opensOutsideCurrentPage(item);
|
|
193
|
+
}
|
|
194
|
+
function moveFocusBeforeClosingItemsRegion() {
|
|
195
|
+
if (!true_default || !itemsRegionElement)
|
|
196
|
+
return;
|
|
197
|
+
const activeElement = document.activeElement;
|
|
198
|
+
if (activeElement instanceof Element && itemsRegionElement.contains(activeElement)) {
|
|
199
|
+
focusMenuToggle();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function focusMenuToggle() {
|
|
203
|
+
const focusTarget = toggleElement ?? navigationBarElement?.querySelector(toggleFocusSelector);
|
|
204
|
+
focusTarget?.focus();
|
|
205
|
+
}
|
|
206
|
+
function handleClick(event) {
|
|
207
|
+
if ($$props.onclick) {
|
|
208
|
+
const currentTarget = event.currentTarget instanceof HTMLElement ? event.currentTarget : navigationBarElement;
|
|
209
|
+
$$props.onclick.call(currentTarget, event);
|
|
210
|
+
}
|
|
211
|
+
if (event.defaultPrevented)
|
|
212
|
+
return;
|
|
213
|
+
const navigationItem = getEventNavigationItem(event);
|
|
214
|
+
if (!navigationItem || !canCloseAfterItemActivation(navigationItem, event))
|
|
215
|
+
return;
|
|
216
|
+
moveFocusBeforeClosingItemsRegion();
|
|
217
|
+
mobileMenuOpen(false);
|
|
218
|
+
}
|
|
182
219
|
function focusAdjacentNavigationItem(currentItem, direction) {
|
|
183
220
|
const items = getNavigationItems();
|
|
184
221
|
if (items.length === 0)
|
|
@@ -203,11 +240,11 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
203
240
|
return;
|
|
204
241
|
if (event.key === "Escape" && $.get(isCollapsible) && $.get(isMobileLayout) && mobileMenuOpen()) {
|
|
205
242
|
mobileMenuOpen(false);
|
|
206
|
-
|
|
243
|
+
focusMenuToggle();
|
|
207
244
|
return;
|
|
208
245
|
}
|
|
209
246
|
const navigationItem = getEventNavigationItem(event);
|
|
210
|
-
if (!navigationItem)
|
|
247
|
+
if (!navigationItem || navigationItem !== event.target)
|
|
211
248
|
return;
|
|
212
249
|
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
213
250
|
event.preventDefault();
|
|
@@ -230,6 +267,7 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
230
267
|
"data-cinder-placement": placement(),
|
|
231
268
|
"data-cinder-label-visibility": showLabels(),
|
|
232
269
|
"data-cinder-menu-toggle-placement": menuTogglePlacement(),
|
|
270
|
+
onclick: handleClick,
|
|
233
271
|
onkeydown: handleKeyDown
|
|
234
272
|
}), [() => classNames("cinder-navigation-bar", $$props.class)]);
|
|
235
273
|
var node = $.child(nav);
|
|
@@ -329,4 +367,4 @@ export {
|
|
|
329
367
|
Navigation_bar as NavigationBar
|
|
330
368
|
};
|
|
331
369
|
|
|
332
|
-
//# debugId=
|
|
370
|
+
//# debugId=D071FB931C6D395164756E2164756E21
|
|
@@ -1053,7 +1053,9 @@ function Sidebar($$anchor, $$props) {
|
|
|
1053
1053
|
return label();
|
|
1054
1054
|
});
|
|
1055
1055
|
const navigationLabel = $6.derived(() => `${$6.get(validatedLabel)} navigation`);
|
|
1056
|
-
const
|
|
1056
|
+
const hasMatchMedia = typeof window !== "undefined" && typeof window.matchMedia === "function";
|
|
1057
|
+
const usesSsrResponsiveFallback = !hasMatchMedia;
|
|
1058
|
+
const mobile = hasMatchMedia ? new MediaQuery2("(max-width: 47.99rem)", false) : { current: false };
|
|
1057
1059
|
const context = {
|
|
1058
1060
|
get collapsed() {
|
|
1059
1061
|
return collapsed();
|
|
@@ -1103,7 +1105,8 @@ function Sidebar($$anchor, $$props) {
|
|
|
1103
1105
|
...rest,
|
|
1104
1106
|
class: $0,
|
|
1105
1107
|
"aria-label": $6.get(validatedLabel),
|
|
1106
|
-
"data-cinder-collapsed": collapsed() ? "" : undefined
|
|
1108
|
+
"data-cinder-collapsed": collapsed() ? "" : undefined,
|
|
1109
|
+
"data-cinder-ssr-mobile-fallback": usesSsrResponsiveFallback ? "" : undefined
|
|
1107
1110
|
}), [
|
|
1108
1111
|
() => classNames("cinder-sidebar", "cinder-sidebar--desktop", $$props.class)
|
|
1109
1112
|
]);
|
|
@@ -1130,4 +1133,4 @@ export {
|
|
|
1130
1133
|
Sidebar
|
|
1131
1134
|
};
|
|
1132
1135
|
|
|
1133
|
-
//# debugId=
|
|
1136
|
+
//# debugId=13D61E15EB9EC3BE64756E2164756E21
|
package/dist/index.js
CHANGED
|
@@ -22182,6 +22182,7 @@ var rest_excludes39 = new Set([
|
|
|
22182
22182
|
"acceptedTypes",
|
|
22183
22183
|
"onsubmit",
|
|
22184
22184
|
"onstop",
|
|
22185
|
+
"oncomposerinput",
|
|
22185
22186
|
"onattachmentadd",
|
|
22186
22187
|
"onattachmentremove",
|
|
22187
22188
|
"onattachmentfailure",
|
|
@@ -22381,6 +22382,9 @@ function Chat_input($$anchor, $$props) {
|
|
|
22381
22382
|
function handleCompositionEnd() {
|
|
22382
22383
|
$116.set(isComposing, false);
|
|
22383
22384
|
}
|
|
22385
|
+
function handleInput() {
|
|
22386
|
+
$$props.oncomposerinput?.(value());
|
|
22387
|
+
}
|
|
22384
22388
|
function focus() {
|
|
22385
22389
|
$116.get(editorElement)?.focus();
|
|
22386
22390
|
}
|
|
@@ -22392,6 +22396,9 @@ function Chat_input($$anchor, $$props) {
|
|
|
22392
22396
|
function getAttachments() {
|
|
22393
22397
|
return [...$116.get(attachments)];
|
|
22394
22398
|
}
|
|
22399
|
+
function getValue() {
|
|
22400
|
+
return value();
|
|
22401
|
+
}
|
|
22395
22402
|
function addFiles(files) {
|
|
22396
22403
|
if (!allowAttachments())
|
|
22397
22404
|
return;
|
|
@@ -22400,7 +22407,7 @@ function Chat_input($$anchor, $$props) {
|
|
|
22400
22407
|
onDestroy5(() => {
|
|
22401
22408
|
$116.get(attachments).forEach((a) => URL.revokeObjectURL(a.previewUrl));
|
|
22402
22409
|
});
|
|
22403
|
-
var $$exports = { focus, clear, getAttachments, addFiles };
|
|
22410
|
+
var $$exports = { focus, clear, getAttachments, getValue, addFiles };
|
|
22404
22411
|
var form = root_96();
|
|
22405
22412
|
$116.attribute_effect(form, ($0) => ({
|
|
22406
22413
|
class: $0,
|
|
@@ -22635,11 +22642,12 @@ function Chat_input($$anchor, $$props) {
|
|
|
22635
22642
|
$116.set_attribute(span, "id", $116.get(shortcutDescriptionId));
|
|
22636
22643
|
$116.set_text(text_4, announcer.message);
|
|
22637
22644
|
});
|
|
22645
|
+
$116.delegated("input", textarea, handleInput);
|
|
22638
22646
|
$116.bind_value(textarea, value);
|
|
22639
22647
|
$116.append($$anchor, form);
|
|
22640
22648
|
return $116.pop($$exports);
|
|
22641
22649
|
}
|
|
22642
|
-
$116.delegate(["click", "change"]);
|
|
22650
|
+
$116.delegate(["click", "input", "change"]);
|
|
22643
22651
|
// src/components/chat/container/scroll-utilities.ts
|
|
22644
22652
|
var DEFAULT_SCROLL_CONFIGURATION = {
|
|
22645
22653
|
bottomThreshold: 150,
|
|
@@ -24007,7 +24015,8 @@ var rest_excludes40 = new Set([
|
|
|
24007
24015
|
"onexpandedchange",
|
|
24008
24016
|
"onattachmentadd",
|
|
24009
24017
|
"onattachmentremove",
|
|
24010
|
-
"onattachmentfailure"
|
|
24018
|
+
"onattachmentfailure",
|
|
24019
|
+
"oncomposerinput"
|
|
24011
24020
|
]);
|
|
24012
24021
|
var root65 = $133.from_html(`<span class="chat-typing-status svelte-932akd"> </span>`);
|
|
24013
24022
|
var root_171 = $133.from_html(`<span class="chat-typing-dot svelte-932akd" aria-hidden="true"></span> <span class="chat-typing-dot svelte-932akd" aria-hidden="true"></span> <span class="chat-typing-dot svelte-932akd" aria-hidden="true"></span>`, 1);
|
|
@@ -24783,6 +24792,12 @@ function Chat($$anchor, $$props) {
|
|
|
24783
24792
|
function focusInput() {
|
|
24784
24793
|
inputRef?.focus();
|
|
24785
24794
|
}
|
|
24795
|
+
function clearInput() {
|
|
24796
|
+
inputRef?.clear();
|
|
24797
|
+
}
|
|
24798
|
+
function getComposerValue() {
|
|
24799
|
+
return inputRef?.getValue() ?? "";
|
|
24800
|
+
}
|
|
24786
24801
|
function beginStreaming(messageId) {
|
|
24787
24802
|
if (streamingScrollRaf !== undefined) {
|
|
24788
24803
|
cancelAnimationFrame(streamingScrollRaf);
|
|
@@ -24848,6 +24863,8 @@ function Chat($$anchor, $$props) {
|
|
|
24848
24863
|
scrollToBottom,
|
|
24849
24864
|
scrollToTop,
|
|
24850
24865
|
focusInput,
|
|
24866
|
+
clearInput,
|
|
24867
|
+
getComposerValue,
|
|
24851
24868
|
beginStreaming,
|
|
24852
24869
|
pushToken,
|
|
24853
24870
|
endStreaming
|
|
@@ -25319,6 +25336,9 @@ function Chat($$anchor, $$props) {
|
|
|
25319
25336
|
get onstop() {
|
|
25320
25337
|
return $133.get($0);
|
|
25321
25338
|
},
|
|
25339
|
+
get oncomposerinput() {
|
|
25340
|
+
return $$props.oncomposerinput;
|
|
25341
|
+
},
|
|
25322
25342
|
get onattachmentadd() {
|
|
25323
25343
|
return $$props.onattachmentadd;
|
|
25324
25344
|
},
|
|
@@ -25387,13 +25407,21 @@ function Chat2($$anchor, $$props) {
|
|
|
25387
25407
|
function focusInput() {
|
|
25388
25408
|
impl?.focusInput();
|
|
25389
25409
|
}
|
|
25410
|
+
function clearInput() {
|
|
25411
|
+
impl?.clearInput();
|
|
25412
|
+
}
|
|
25413
|
+
function getComposerValue() {
|
|
25414
|
+
return impl?.getComposerValue() ?? "";
|
|
25415
|
+
}
|
|
25390
25416
|
var $$exports = {
|
|
25391
25417
|
beginStreaming,
|
|
25392
25418
|
pushToken,
|
|
25393
25419
|
endStreaming,
|
|
25394
25420
|
scrollToBottom,
|
|
25395
25421
|
scrollToTop,
|
|
25396
|
-
focusInput
|
|
25422
|
+
focusInput,
|
|
25423
|
+
clearInput,
|
|
25424
|
+
getComposerValue
|
|
25397
25425
|
};
|
|
25398
25426
|
$134.bind_this(Chat($$anchor, $134.spread_props({
|
|
25399
25427
|
get class() {
|
|
@@ -52075,6 +52103,7 @@ var rest_excludes113 = new Set([
|
|
|
52075
52103
|
"data-cinder-placement",
|
|
52076
52104
|
"data-cinder-label-visibility",
|
|
52077
52105
|
"data-cinder-menu-toggle-placement",
|
|
52106
|
+
"onclick",
|
|
52078
52107
|
"onkeydown"
|
|
52079
52108
|
]);
|
|
52080
52109
|
var root164 = $254.from_html(`<div class="cinder-navigation-bar__menu-toggle"><!></div>`);
|
|
@@ -52088,6 +52117,7 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
52088
52117
|
const FALLBACK_ROOT_FONT_SIZE_PX = 16;
|
|
52089
52118
|
let placement = $254.prop($$props, "placement", 3, "top"), showLabels = $254.prop($$props, "showLabels", 3, "always"), menuTogglePlacement = $254.prop($$props, "menuTogglePlacement", 3, "after-brand"), mobileMenuOpen = $254.prop($$props, "mobileMenuOpen", 15, false), label = $254.prop($$props, "label", 3, "Main navigation"), rest = $254.rest_props($$props, rest_excludes113);
|
|
52090
52119
|
const navigationItemSelector = "[data-cinder-navigation-item]";
|
|
52120
|
+
const toggleFocusSelector = '.cinder-navigation-bar__menu-toggle button, .cinder-navigation-bar__menu-toggle [href], .cinder-navigation-bar__menu-toggle input, .cinder-navigation-bar__menu-toggle select, .cinder-navigation-bar__menu-toggle textarea, .cinder-navigation-bar__menu-toggle [tabindex]:not([tabindex="-1"])';
|
|
52091
52121
|
const isCollapsible = $254.derived(() => placement() === "top" && $$props.menuToggle !== undefined);
|
|
52092
52122
|
let isMobileLayout = $254.state(false);
|
|
52093
52123
|
const variant = $254.derived(() => placement() === "bottom" ? "mobile" : $254.get(isCollapsible) && $254.get(isMobileLayout) && mobileMenuOpen() ? "mobile" : "horizontal");
|
|
@@ -52160,15 +52190,50 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
52160
52190
|
return item.getAttribute("aria-disabled") !== "true" && !item.hasAttribute("disabled");
|
|
52161
52191
|
}
|
|
52162
52192
|
function getEventNavigationItem(event24) {
|
|
52163
|
-
if (!(event24.target instanceof
|
|
52193
|
+
if (!(event24.target instanceof Element) || !itemsRegionElement)
|
|
52164
52194
|
return null;
|
|
52165
52195
|
const navigationItem = event24.target.closest(navigationItemSelector);
|
|
52166
52196
|
if (!navigationItem || !itemsRegionElement.contains(navigationItem))
|
|
52167
52197
|
return null;
|
|
52168
|
-
if (navigationItem !== event24.target)
|
|
52169
|
-
return null;
|
|
52170
52198
|
return navigationItem;
|
|
52171
52199
|
}
|
|
52200
|
+
function isModifiedClick(event24) {
|
|
52201
|
+
return event24.button !== 0 || event24.altKey || event24.ctrlKey || event24.metaKey || event24.shiftKey;
|
|
52202
|
+
}
|
|
52203
|
+
function opensOutsideCurrentPage(item) {
|
|
52204
|
+
if (!(item instanceof HTMLAnchorElement))
|
|
52205
|
+
return false;
|
|
52206
|
+
const target = item.getAttribute("target");
|
|
52207
|
+
return item.hasAttribute("download") || target !== null && target.trim() !== "" && target.trim().toLowerCase() !== "_self";
|
|
52208
|
+
}
|
|
52209
|
+
function canCloseAfterItemActivation(item, event24) {
|
|
52210
|
+
return $254.get(isCollapsible) && $254.get(isMobileLayout) && mobileMenuOpen() && isEnabledNavigationItem(item) && !isModifiedClick(event24) && !opensOutsideCurrentPage(item);
|
|
52211
|
+
}
|
|
52212
|
+
function moveFocusBeforeClosingItemsRegion() {
|
|
52213
|
+
if (!true_default || !itemsRegionElement)
|
|
52214
|
+
return;
|
|
52215
|
+
const activeElement = document.activeElement;
|
|
52216
|
+
if (activeElement instanceof Element && itemsRegionElement.contains(activeElement)) {
|
|
52217
|
+
focusMenuToggle();
|
|
52218
|
+
}
|
|
52219
|
+
}
|
|
52220
|
+
function focusMenuToggle() {
|
|
52221
|
+
const focusTarget = toggleElement ?? navigationBarElement?.querySelector(toggleFocusSelector);
|
|
52222
|
+
focusTarget?.focus();
|
|
52223
|
+
}
|
|
52224
|
+
function handleClick(event24) {
|
|
52225
|
+
if ($$props.onclick) {
|
|
52226
|
+
const currentTarget = event24.currentTarget instanceof HTMLElement ? event24.currentTarget : navigationBarElement;
|
|
52227
|
+
$$props.onclick.call(currentTarget, event24);
|
|
52228
|
+
}
|
|
52229
|
+
if (event24.defaultPrevented)
|
|
52230
|
+
return;
|
|
52231
|
+
const navigationItem = getEventNavigationItem(event24);
|
|
52232
|
+
if (!navigationItem || !canCloseAfterItemActivation(navigationItem, event24))
|
|
52233
|
+
return;
|
|
52234
|
+
moveFocusBeforeClosingItemsRegion();
|
|
52235
|
+
mobileMenuOpen(false);
|
|
52236
|
+
}
|
|
52172
52237
|
function focusAdjacentNavigationItem(currentItem, direction) {
|
|
52173
52238
|
const items = getNavigationItems();
|
|
52174
52239
|
if (items.length === 0)
|
|
@@ -52193,11 +52258,11 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
52193
52258
|
return;
|
|
52194
52259
|
if (event24.key === "Escape" && $254.get(isCollapsible) && $254.get(isMobileLayout) && mobileMenuOpen()) {
|
|
52195
52260
|
mobileMenuOpen(false);
|
|
52196
|
-
|
|
52261
|
+
focusMenuToggle();
|
|
52197
52262
|
return;
|
|
52198
52263
|
}
|
|
52199
52264
|
const navigationItem = getEventNavigationItem(event24);
|
|
52200
|
-
if (!navigationItem)
|
|
52265
|
+
if (!navigationItem || navigationItem !== event24.target)
|
|
52201
52266
|
return;
|
|
52202
52267
|
if (event24.key === "ArrowLeft" || event24.key === "ArrowRight") {
|
|
52203
52268
|
event24.preventDefault();
|
|
@@ -52220,6 +52285,7 @@ function Navigation_bar($$anchor, $$props) {
|
|
|
52220
52285
|
"data-cinder-placement": placement(),
|
|
52221
52286
|
"data-cinder-label-visibility": showLabels(),
|
|
52222
52287
|
"data-cinder-menu-toggle-placement": menuTogglePlacement(),
|
|
52288
|
+
onclick: handleClick,
|
|
52223
52289
|
onkeydown: handleKeyDown
|
|
52224
52290
|
}), [() => classNames("cinder-navigation-bar", $$props.class)]);
|
|
52225
52291
|
var node = $254.child(nav);
|
|
@@ -63660,7 +63726,9 @@ function Sidebar($$anchor, $$props) {
|
|
|
63660
63726
|
return label();
|
|
63661
63727
|
});
|
|
63662
63728
|
const navigationLabel = $284.derived(() => `${$284.get(validatedLabel)} navigation`);
|
|
63663
|
-
const
|
|
63729
|
+
const hasMatchMedia = typeof window !== "undefined" && typeof window.matchMedia === "function";
|
|
63730
|
+
const usesSsrResponsiveFallback = !hasMatchMedia;
|
|
63731
|
+
const mobile = hasMatchMedia ? new MediaQuery2("(max-width: 47.99rem)", false) : { current: false };
|
|
63664
63732
|
const context = {
|
|
63665
63733
|
get collapsed() {
|
|
63666
63734
|
return collapsed();
|
|
@@ -63710,7 +63778,8 @@ function Sidebar($$anchor, $$props) {
|
|
|
63710
63778
|
...rest,
|
|
63711
63779
|
class: $0,
|
|
63712
63780
|
"aria-label": $284.get(validatedLabel),
|
|
63713
|
-
"data-cinder-collapsed": collapsed() ? "" : undefined
|
|
63781
|
+
"data-cinder-collapsed": collapsed() ? "" : undefined,
|
|
63782
|
+
"data-cinder-ssr-mobile-fallback": usesSsrResponsiveFallback ? "" : undefined
|
|
63714
63783
|
}), [
|
|
63715
63784
|
() => classNames("cinder-sidebar", "cinder-sidebar--desktop", $$props.class)
|
|
63716
63785
|
]);
|
|
@@ -74446,4 +74515,4 @@ export {
|
|
|
74446
74515
|
AccessGateExport as AccessGate
|
|
74447
74516
|
};
|
|
74448
74517
|
|
|
74449
|
-
//# debugId=
|
|
74518
|
+
//# debugId=D4AB81D9615DF39E64756E2164756E21
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
findUnreadBoundaryIndex,
|
|
24
24
|
isAtBottom,
|
|
25
25
|
shouldShowJumpToLatest
|
|
26
|
-
} from "../../index.server-
|
|
26
|
+
} from "../../index.server-v4zabrsx.js";
|
|
27
27
|
import"../../index.server-qkfd0qa7.js";
|
|
28
28
|
import"../../index.server-kb6w1a7c.js";
|
|
29
29
|
import"../../index.server-317enkqq.js";
|
package/dist/server/index.js
CHANGED
|
@@ -164,7 +164,7 @@ import"./index.server-d6j2jmqg.js";
|
|
|
164
164
|
import"./index.server-amfq2v2p.js";
|
|
165
165
|
import {
|
|
166
166
|
sidebar_default
|
|
167
|
-
} from "./index.server-
|
|
167
|
+
} from "./index.server-69epaape.js";
|
|
168
168
|
import {
|
|
169
169
|
skeleton_default
|
|
170
170
|
} from "./index.server-5fypkt27.js";
|
|
@@ -247,7 +247,7 @@ import {
|
|
|
247
247
|
} from "./index.server-dj47xy3x.js";
|
|
248
248
|
import {
|
|
249
249
|
navigation_bar_default
|
|
250
|
-
} from "./index.server-
|
|
250
|
+
} from "./index.server-5tf22d6e.js";
|
|
251
251
|
import {
|
|
252
252
|
navigation_item_default
|
|
253
253
|
} from "./index.server-ncdt0xb7.js";
|
|
@@ -566,7 +566,7 @@ import {
|
|
|
566
566
|
} from "./index.server-tbyd4re7.js";
|
|
567
567
|
import {
|
|
568
568
|
chat_default
|
|
569
|
-
} from "./index.server-
|
|
569
|
+
} from "./index.server-v4zabrsx.js";
|
|
570
570
|
import"./index.server-qkfd0qa7.js";
|
|
571
571
|
import {
|
|
572
572
|
useIntersection
|
|
@@ -28,12 +28,14 @@ function Navigation_bar($$renderer, $$props) {
|
|
|
28
28
|
"data-cinder-placement": _dataCinderPlacement,
|
|
29
29
|
"data-cinder-label-visibility": _dataCinderLabelVisibility,
|
|
30
30
|
"data-cinder-menu-toggle-placement": _dataCinderMenuTogglePlacement,
|
|
31
|
+
onclick: consumerOnClick,
|
|
31
32
|
onkeydown: consumerOnKeyDown,
|
|
32
33
|
$$slots,
|
|
33
34
|
$$events,
|
|
34
35
|
...rest
|
|
35
36
|
} = $$props;
|
|
36
37
|
const navigationItemSelector = "[data-cinder-navigation-item]";
|
|
38
|
+
const toggleFocusSelector = '.cinder-navigation-bar__menu-toggle button, .cinder-navigation-bar__menu-toggle [href], .cinder-navigation-bar__menu-toggle input, .cinder-navigation-bar__menu-toggle select, .cinder-navigation-bar__menu-toggle textarea, .cinder-navigation-bar__menu-toggle [tabindex]:not([tabindex="-1"])';
|
|
37
39
|
const isCollapsible = $.derived(() => placement === "top" && menuToggle !== undefined);
|
|
38
40
|
let isMobileLayout = false;
|
|
39
41
|
const variant = $.derived(() => placement === "bottom" ? "mobile" : isCollapsible() && isMobileLayout && mobileMenuOpen ? "mobile" : "horizontal");
|
|
@@ -67,15 +69,50 @@ function Navigation_bar($$renderer, $$props) {
|
|
|
67
69
|
return item.getAttribute("aria-disabled") !== "true" && !item.hasAttribute("disabled");
|
|
68
70
|
}
|
|
69
71
|
function getEventNavigationItem(event) {
|
|
70
|
-
if (!(event.target instanceof
|
|
72
|
+
if (!(event.target instanceof Element) || !itemsRegionElement)
|
|
71
73
|
return null;
|
|
72
74
|
const navigationItem = event.target.closest(navigationItemSelector);
|
|
73
75
|
if (!navigationItem || !itemsRegionElement.contains(navigationItem))
|
|
74
76
|
return null;
|
|
75
|
-
if (navigationItem !== event.target)
|
|
76
|
-
return null;
|
|
77
77
|
return navigationItem;
|
|
78
78
|
}
|
|
79
|
+
function isModifiedClick(event) {
|
|
80
|
+
return event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
81
|
+
}
|
|
82
|
+
function opensOutsideCurrentPage(item) {
|
|
83
|
+
if (!(item instanceof HTMLAnchorElement))
|
|
84
|
+
return false;
|
|
85
|
+
const target = item.getAttribute("target");
|
|
86
|
+
return item.hasAttribute("download") || target !== null && target.trim() !== "" && target.trim().toLowerCase() !== "_self";
|
|
87
|
+
}
|
|
88
|
+
function canCloseAfterItemActivation(item, event) {
|
|
89
|
+
return isCollapsible() && isMobileLayout && mobileMenuOpen && isEnabledNavigationItem(item) && !isModifiedClick(event) && !opensOutsideCurrentPage(item);
|
|
90
|
+
}
|
|
91
|
+
function moveFocusBeforeClosingItemsRegion() {
|
|
92
|
+
if (!false_default || !itemsRegionElement)
|
|
93
|
+
return;
|
|
94
|
+
const activeElement = document.activeElement;
|
|
95
|
+
if (activeElement instanceof Element && itemsRegionElement.contains(activeElement)) {
|
|
96
|
+
focusMenuToggle();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function focusMenuToggle() {
|
|
100
|
+
const focusTarget = toggleElement ?? navigationBarElement?.querySelector(toggleFocusSelector);
|
|
101
|
+
focusTarget?.focus();
|
|
102
|
+
}
|
|
103
|
+
function handleClick(event) {
|
|
104
|
+
if (consumerOnClick) {
|
|
105
|
+
const currentTarget = event.currentTarget instanceof HTMLElement ? event.currentTarget : navigationBarElement;
|
|
106
|
+
consumerOnClick.call(currentTarget, event);
|
|
107
|
+
}
|
|
108
|
+
if (event.defaultPrevented)
|
|
109
|
+
return;
|
|
110
|
+
const navigationItem = getEventNavigationItem(event);
|
|
111
|
+
if (!navigationItem || !canCloseAfterItemActivation(navigationItem, event))
|
|
112
|
+
return;
|
|
113
|
+
moveFocusBeforeClosingItemsRegion();
|
|
114
|
+
mobileMenuOpen = false;
|
|
115
|
+
}
|
|
79
116
|
function focusAdjacentNavigationItem(currentItem, direction) {
|
|
80
117
|
const items2 = getNavigationItems();
|
|
81
118
|
if (items2.length === 0)
|
|
@@ -100,11 +137,11 @@ function Navigation_bar($$renderer, $$props) {
|
|
|
100
137
|
return;
|
|
101
138
|
if (event.key === "Escape" && isCollapsible() && isMobileLayout && mobileMenuOpen) {
|
|
102
139
|
mobileMenuOpen = false;
|
|
103
|
-
|
|
140
|
+
focusMenuToggle();
|
|
104
141
|
return;
|
|
105
142
|
}
|
|
106
143
|
const navigationItem = getEventNavigationItem(event);
|
|
107
|
-
if (!navigationItem)
|
|
144
|
+
if (!navigationItem || navigationItem !== event.target)
|
|
108
145
|
return;
|
|
109
146
|
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
110
147
|
event.preventDefault();
|
|
@@ -181,4 +218,4 @@ function Navigation_bar($$renderer, $$props) {
|
|
|
181
218
|
var navigation_bar_default = Navigation_bar;
|
|
182
219
|
export { Navigation_bar, navigation_bar_default };
|
|
183
220
|
|
|
184
|
-
//# debugId=
|
|
221
|
+
//# debugId=7CE77ABFF189F35064756E2164756E21
|
|
@@ -44,7 +44,9 @@ function Sidebar($$renderer, $$props) {
|
|
|
44
44
|
return label;
|
|
45
45
|
});
|
|
46
46
|
const navigationLabel = $.derived(() => `${validatedLabel()} navigation`);
|
|
47
|
-
const
|
|
47
|
+
const hasMatchMedia = typeof window !== "undefined" && typeof window.matchMedia === "function";
|
|
48
|
+
const usesSsrResponsiveFallback = !hasMatchMedia;
|
|
49
|
+
const mobile = hasMatchMedia ? new MediaQuery("(max-width: 47.99rem)", false) : { current: false };
|
|
48
50
|
const context = {
|
|
49
51
|
get collapsed() {
|
|
50
52
|
return collapsed;
|
|
@@ -117,7 +119,8 @@ function Sidebar($$renderer, $$props) {
|
|
|
117
119
|
...rest,
|
|
118
120
|
class: $.clsx(classNames("cinder-sidebar", "cinder-sidebar--desktop", className)),
|
|
119
121
|
"aria-label": validatedLabel(),
|
|
120
|
-
"data-cinder-collapsed": collapsed ? "" : undefined
|
|
122
|
+
"data-cinder-collapsed": collapsed ? "" : undefined,
|
|
123
|
+
"data-cinder-ssr-mobile-fallback": usesSsrResponsiveFallback ? "" : undefined
|
|
121
124
|
})}>`);
|
|
122
125
|
sidebarContents($$renderer3, false);
|
|
123
126
|
$$renderer3.push(`<!----></aside>`);
|
|
@@ -138,4 +141,4 @@ function Sidebar($$renderer, $$props) {
|
|
|
138
141
|
var sidebar_default = Sidebar;
|
|
139
142
|
export { Sidebar, sidebar_default };
|
|
140
143
|
|
|
141
|
-
//# debugId=
|
|
144
|
+
//# debugId=4AE415A204BE6FC264756E2164756E21
|
|
@@ -1267,6 +1267,7 @@ function Chat_input($$renderer, $$props) {
|
|
|
1267
1267
|
],
|
|
1268
1268
|
onsubmit,
|
|
1269
1269
|
onstop,
|
|
1270
|
+
oncomposerinput,
|
|
1270
1271
|
onattachmentadd,
|
|
1271
1272
|
onattachmentremove,
|
|
1272
1273
|
onattachmentfailure,
|
|
@@ -1441,6 +1442,9 @@ function Chat_input($$renderer, $$props) {
|
|
|
1441
1442
|
function handleCompositionEnd() {
|
|
1442
1443
|
isComposing = false;
|
|
1443
1444
|
}
|
|
1445
|
+
function handleInput() {
|
|
1446
|
+
oncomposerinput?.(value);
|
|
1447
|
+
}
|
|
1444
1448
|
function focus() {
|
|
1445
1449
|
editorElement?.focus();
|
|
1446
1450
|
}
|
|
@@ -1452,6 +1456,9 @@ function Chat_input($$renderer, $$props) {
|
|
|
1452
1456
|
function getAttachments() {
|
|
1453
1457
|
return [...attachments];
|
|
1454
1458
|
}
|
|
1459
|
+
function getValue() {
|
|
1460
|
+
return value;
|
|
1461
|
+
}
|
|
1455
1462
|
function addFiles(files) {
|
|
1456
1463
|
if (!allowAttachments)
|
|
1457
1464
|
return;
|
|
@@ -1565,7 +1572,7 @@ function Chat_input($$renderer, $$props) {
|
|
|
1565
1572
|
$$renderer2.push("<!--[-1-->");
|
|
1566
1573
|
}
|
|
1567
1574
|
$$renderer2.push(`<!--]--> <div aria-live="polite" aria-atomic="true" class="sr-only svelte-1tzweuh">${$19.escape(announcer.message)}</div></form>`);
|
|
1568
|
-
$19.bind_props($$props, { value, focus, clear, getAttachments, addFiles });
|
|
1575
|
+
$19.bind_props($$props, { value, focus, clear, getAttachments, getValue, addFiles });
|
|
1569
1576
|
}, Chat_input);
|
|
1570
1577
|
}
|
|
1571
1578
|
// src/components/chat/container/scroll-utilities.ts
|
|
@@ -2731,6 +2738,7 @@ function Chat($$renderer, $$props) {
|
|
|
2731
2738
|
onattachmentadd,
|
|
2732
2739
|
onattachmentremove,
|
|
2733
2740
|
onattachmentfailure,
|
|
2741
|
+
oncomposerinput,
|
|
2734
2742
|
$$slots,
|
|
2735
2743
|
$$events,
|
|
2736
2744
|
...rest
|
|
@@ -3356,6 +3364,12 @@ function Chat($$renderer, $$props) {
|
|
|
3356
3364
|
function focusInput() {
|
|
3357
3365
|
inputRef?.focus();
|
|
3358
3366
|
}
|
|
3367
|
+
function clearInput() {
|
|
3368
|
+
inputRef?.clear();
|
|
3369
|
+
}
|
|
3370
|
+
function getComposerValue() {
|
|
3371
|
+
return inputRef?.getValue() ?? "";
|
|
3372
|
+
}
|
|
3359
3373
|
function beginStreaming(messageId) {
|
|
3360
3374
|
if (streamingScrollRaf !== undefined) {
|
|
3361
3375
|
cancelAnimationFrame(streamingScrollRaf);
|
|
@@ -3646,6 +3660,7 @@ function Chat($$renderer, $$props) {
|
|
|
3646
3660
|
sending: streaming,
|
|
3647
3661
|
allowAttachments: allowAttachments(),
|
|
3648
3662
|
onstop: streaming ? handleStopGenerating : undefined,
|
|
3663
|
+
oncomposerinput,
|
|
3649
3664
|
onattachmentadd,
|
|
3650
3665
|
onattachmentremove,
|
|
3651
3666
|
onattachmentfailure
|
|
@@ -3665,6 +3680,8 @@ function Chat($$renderer, $$props) {
|
|
|
3665
3680
|
scrollToBottom,
|
|
3666
3681
|
scrollToTop,
|
|
3667
3682
|
focusInput,
|
|
3683
|
+
clearInput,
|
|
3684
|
+
getComposerValue,
|
|
3668
3685
|
beginStreaming,
|
|
3669
3686
|
pushToken,
|
|
3670
3687
|
endStreaming
|
|
@@ -3696,6 +3713,12 @@ function Chat2($$renderer, $$props) {
|
|
|
3696
3713
|
function focusInput() {
|
|
3697
3714
|
impl?.focusInput();
|
|
3698
3715
|
}
|
|
3716
|
+
function clearInput() {
|
|
3717
|
+
impl?.clearInput();
|
|
3718
|
+
}
|
|
3719
|
+
function getComposerValue() {
|
|
3720
|
+
return impl?.getComposerValue() ?? "";
|
|
3721
|
+
}
|
|
3699
3722
|
Chat($$renderer2, $36.spread_props([{ class: mergedClassName() }, rest]));
|
|
3700
3723
|
$36.bind_props($$props, {
|
|
3701
3724
|
beginStreaming,
|
|
@@ -3703,7 +3726,9 @@ function Chat2($$renderer, $$props) {
|
|
|
3703
3726
|
endStreaming,
|
|
3704
3727
|
scrollToBottom,
|
|
3705
3728
|
scrollToTop,
|
|
3706
|
-
focusInput
|
|
3729
|
+
focusInput,
|
|
3730
|
+
clearInput,
|
|
3731
|
+
getComposerValue
|
|
3707
3732
|
});
|
|
3708
3733
|
}, Chat2);
|
|
3709
3734
|
}
|
|
@@ -3794,4 +3819,4 @@ function Chat_artifact_layout($$renderer, $$props) {
|
|
|
3794
3819
|
var chat_default = Chat2;
|
|
3795
3820
|
export { Chat_date_separator, Message_content, Tool_call_group, Message_attachments, Chat_message, deriveAttachmentKind, Chat_attachment_preview, Chat_input, DEFAULT_SCROLL_CONFIGURATION, isAtBottom, shouldShowJumpToLatest, calculateUnreadCount, findUnreadBoundaryIndex, calculateScrollToBottom, extractTimestamp, Chat2 as Chat, createConversation, appendMessages2 as appendMessages, appendUserMessage2 as appendUserMessage, appendAssistantMessage2 as appendAssistantMessage, Artifact_panel, Artifact_viewer, Chat_artifact_layout, chat_default };
|
|
3796
3821
|
|
|
3797
|
-
//# debugId=
|
|
3822
|
+
//# debugId=48E7964ABAFE717A64756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lostgradient/cinder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "A Svelte 5 component library and design system focused on accessibility, theming, and per-component tree-shaking.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|
|
@@ -6427,10 +6427,12 @@
|
|
|
6427
6427
|
"@testing-library/jest-dom": "^6.9.1",
|
|
6428
6428
|
"@testing-library/svelte": "^5.2.7",
|
|
6429
6429
|
"@types/bun": "^1.3.11",
|
|
6430
|
+
"@types/js-yaml": "^4.0.9",
|
|
6430
6431
|
"@types/qrcode": "^1.5.6",
|
|
6431
6432
|
"chalk": "^5.6.2",
|
|
6432
6433
|
"change-case": "^5.4.4",
|
|
6433
6434
|
"happy-dom": "^15.11.7",
|
|
6435
|
+
"js-yaml": "^4.1.0",
|
|
6434
6436
|
"lucide-svelte": "^0.503.0",
|
|
6435
6437
|
"oxlint": "^1.56.0",
|
|
6436
6438
|
"oxlint-tsgolint": "^0.17.0",
|
|
@@ -164,6 +164,11 @@
|
|
|
164
164
|
"name": "onattachmentremove",
|
|
165
165
|
"reason": "function-or-snippet"
|
|
166
166
|
},
|
|
167
|
+
{
|
|
168
|
+
"name": "oncomposerinput",
|
|
169
|
+
"reason": "function-or-snippet",
|
|
170
|
+
"description": "Called with the composer's current plain-text value on every composer\ninput event. Lets a consumer build slash-command, mention, or autocomplete\nUX without reaching into `.chat-input-editor` DOM directly."
|
|
171
|
+
},
|
|
167
172
|
{
|
|
168
173
|
"name": "ondeny",
|
|
169
174
|
"reason": "function-or-snippet",
|
|
@@ -191,6 +191,12 @@ const schema = {
|
|
|
191
191
|
name: 'onattachmentremove',
|
|
192
192
|
reason: 'function-or-snippet',
|
|
193
193
|
},
|
|
194
|
+
{
|
|
195
|
+
name: 'oncomposerinput',
|
|
196
|
+
reason: 'function-or-snippet',
|
|
197
|
+
description:
|
|
198
|
+
"Called with the composer's current plain-text value on every composer\ninput event. Lets a consumer build slash-command, mention, or autocomplete\nUX without reaching into `.chat-input-editor` DOM directly.",
|
|
199
|
+
},
|
|
194
200
|
{
|
|
195
201
|
name: 'ondeny',
|
|
196
202
|
reason: 'function-or-snippet',
|
|
@@ -42,6 +42,14 @@ export function scrollToTop() {
|
|
|
42
42
|
export function focusInput() {
|
|
43
43
|
impl?.focusInput();
|
|
44
44
|
}
|
|
45
|
+
/** Clear the composer's current content. No-op until mounted. */
|
|
46
|
+
export function clearInput() {
|
|
47
|
+
impl?.clearInput();
|
|
48
|
+
}
|
|
49
|
+
/** Read the composer's current plain-text value. Returns '' until mounted. */
|
|
50
|
+
export function getComposerValue() {
|
|
51
|
+
return impl?.getComposerValue() ?? '';
|
|
52
|
+
}
|
|
45
53
|
</script>
|
|
46
54
|
|
|
47
55
|
<ChatImplementation bind:this={impl} class={mergedClassName} {...rest} />
|
|
@@ -243,4 +243,10 @@ export type ChatProps = Omit<HTMLAttributes<HTMLElement>, 'class' | 'onsubmit'>
|
|
|
243
243
|
onattachmentadd?: (attachment: ChatAttachment) => void;
|
|
244
244
|
onattachmentremove?: (attachment: ChatAttachment) => void;
|
|
245
245
|
onattachmentfailure?: (file: File, error: string) => void;
|
|
246
|
+
/**
|
|
247
|
+
* Called with the composer's current plain-text value on every composer
|
|
248
|
+
* input event. Lets a consumer build slash-command, mention, or autocomplete
|
|
249
|
+
* UX without reaching into `.chat-input-editor` DOM directly.
|
|
250
|
+
*/
|
|
251
|
+
oncomposerinput?: (value: string) => void;
|
|
246
252
|
};
|
|
@@ -26,7 +26,7 @@ import { useChatReadReceipts } from './use-chat-read-receipts.svelte.ts';
|
|
|
26
26
|
import ChatParticipantTyping from './chat-participant-typing.svelte';
|
|
27
27
|
import ChatReadReceipt from '../message/chat-read-receipt.svelte';
|
|
28
28
|
const noopAttachment = () => { };
|
|
29
|
-
let { id, conversation, atBottom = $bindable(true), unreadCount = $bindable(0), newMessageIndicatorVisible = $bindable(false), class: className, surfaceMode = 'default', density = 'comfortable', variant = 'bubble', bottomThreshold = DEFAULT_SCROLL_CONFIGURATION.bottomThreshold, jumpThreshold = DEFAULT_SCROLL_CONFIGURATION.jumpThreshold, streaming = false, streamingStatus, capabilities, virtualized = false, virtualizationEstimatedRowHeight = 88, virtualizationOverscan = 3, virtualizationInitialHeight = 640, moreHistoryAvailable = true, loadEarlierLabel = 'Load earlier messages', loadingEarlierLabel = 'Loading earlier messages', header, empty, emptyPrompts, messageActions, messageStatus, row, messagePart, viewportAttachment, typingParticipants, readReceipts, adapter, onadaptererror, onpushmessage, ontypingchange, onreadreceipt, onsubmit, onretry, onedit, onapprove, ondeny, messageReasoning, messageSteps, messageSuggestions, onsuggestionselect, onloadhistory, onstopgenerating, onjumptolatest, onscrollstatechange, onunreadindicatorchange, onexpandedchange, onattachmentadd, onattachmentremove, onattachmentfailure, ...rest } = $props();
|
|
29
|
+
let { id, conversation, atBottom = $bindable(true), unreadCount = $bindable(0), newMessageIndicatorVisible = $bindable(false), class: className, surfaceMode = 'default', density = 'comfortable', variant = 'bubble', bottomThreshold = DEFAULT_SCROLL_CONFIGURATION.bottomThreshold, jumpThreshold = DEFAULT_SCROLL_CONFIGURATION.jumpThreshold, streaming = false, streamingStatus, capabilities, virtualized = false, virtualizationEstimatedRowHeight = 88, virtualizationOverscan = 3, virtualizationInitialHeight = 640, moreHistoryAvailable = true, loadEarlierLabel = 'Load earlier messages', loadingEarlierLabel = 'Loading earlier messages', header, empty, emptyPrompts, messageActions, messageStatus, row, messagePart, viewportAttachment, typingParticipants, readReceipts, adapter, onadaptererror, onpushmessage, ontypingchange, onreadreceipt, onsubmit, onretry, onedit, onapprove, ondeny, messageReasoning, messageSteps, messageSuggestions, onsuggestionselect, onloadhistory, onstopgenerating, onjumptolatest, onscrollstatechange, onunreadindicatorchange, onexpandedchange, onattachmentadd, onattachmentremove, onattachmentfailure, oncomposerinput, ...rest } = $props();
|
|
30
30
|
// ==========================================================================
|
|
31
31
|
// Refs and Internal State
|
|
32
32
|
// ==========================================================================
|
|
@@ -1061,6 +1061,14 @@ export function scrollToTop() {
|
|
|
1061
1061
|
export function focusInput() {
|
|
1062
1062
|
inputRef?.focus();
|
|
1063
1063
|
}
|
|
1064
|
+
/** Clear the composer's current content. */
|
|
1065
|
+
export function clearInput() {
|
|
1066
|
+
inputRef?.clear();
|
|
1067
|
+
}
|
|
1068
|
+
/** Read the composer's current plain-text value. */
|
|
1069
|
+
export function getComposerValue() {
|
|
1070
|
+
return inputRef?.getValue() ?? '';
|
|
1071
|
+
}
|
|
1064
1072
|
/**
|
|
1065
1073
|
* Begin streaming content for a specific message.
|
|
1066
1074
|
* The message should already exist in the conversation.
|
|
@@ -1405,6 +1413,7 @@ function virtualRowAttachment(row) {
|
|
|
1405
1413
|
sending={streaming}
|
|
1406
1414
|
{allowAttachments}
|
|
1407
1415
|
onstop={streaming ? handleStopGenerating : undefined}
|
|
1416
|
+
{oncomposerinput}
|
|
1408
1417
|
{onattachmentadd}
|
|
1409
1418
|
{onattachmentremove}
|
|
1410
1419
|
{onattachmentfailure}
|
|
@@ -55,7 +55,7 @@ acceptedTypes = [
|
|
|
55
55
|
'application/x-sh',
|
|
56
56
|
'application/sql',
|
|
57
57
|
'application/toml',
|
|
58
|
-
], onsubmit, onstop, onattachmentadd, onattachmentremove, onattachmentfailure, actions, ...rest } = $props();
|
|
58
|
+
], onsubmit, onstop, oncomposerinput, onattachmentadd, onattachmentremove, onattachmentfailure, actions, ...rest } = $props();
|
|
59
59
|
const resolvedComposerLabel = $derived(composerLabel.trim() || 'Message');
|
|
60
60
|
// Derived: show stop button when sending and onstop is provided
|
|
61
61
|
const showStopButton = $derived(sending && onstop !== undefined);
|
|
@@ -284,6 +284,12 @@ function handleCompositionStart() {
|
|
|
284
284
|
function handleCompositionEnd() {
|
|
285
285
|
isComposing = false;
|
|
286
286
|
}
|
|
287
|
+
// Fires after `bind:value` has already applied the textarea's new value
|
|
288
|
+
// (Svelte merges the binding's own input listener with this handler on the
|
|
289
|
+
// same event), so `value` here is always current — never one keystroke stale.
|
|
290
|
+
function handleInput() {
|
|
291
|
+
oncomposerinput?.(value);
|
|
292
|
+
}
|
|
287
293
|
// =========================================================================
|
|
288
294
|
// Imperative API
|
|
289
295
|
// =========================================================================
|
|
@@ -298,6 +304,9 @@ export function clear() {
|
|
|
298
304
|
export function getAttachments() {
|
|
299
305
|
return [...attachments];
|
|
300
306
|
}
|
|
307
|
+
export function getValue() {
|
|
308
|
+
return value;
|
|
309
|
+
}
|
|
301
310
|
export function addFiles(files) {
|
|
302
311
|
if (!allowAttachments)
|
|
303
312
|
return;
|
|
@@ -358,6 +367,7 @@ onDestroy(() => {
|
|
|
358
367
|
bind:this={editorElement}
|
|
359
368
|
id={`${id}-editor`}
|
|
360
369
|
bind:value
|
|
370
|
+
oninput={handleInput}
|
|
361
371
|
{placeholder}
|
|
362
372
|
aria-label={resolvedComposerLabel}
|
|
363
373
|
{disabled}
|
|
@@ -10,8 +10,9 @@ const FALLBACK_ROOT_FONT_SIZE_PX = 16;
|
|
|
10
10
|
const regionId = $props.id();
|
|
11
11
|
let { class: className, placement = 'top', showLabels = 'always', menuTogglePlacement = 'after-brand', brand, items, actions, menuToggle, mobileMenuOpen = $bindable(false), label = 'Main navigation',
|
|
12
12
|
// Strip these from rest so they cannot collide with internal attributes.
|
|
13
|
-
'aria-label': _ariaLabel, 'data-collapsible': _dataCollapsible, 'data-cinder-placement': _dataCinderPlacement, 'data-cinder-label-visibility': _dataCinderLabelVisibility, 'data-cinder-menu-toggle-placement': _dataCinderMenuTogglePlacement, onkeydown: consumerOnKeyDown, ...rest } = $props();
|
|
13
|
+
'aria-label': _ariaLabel, 'data-collapsible': _dataCollapsible, 'data-cinder-placement': _dataCinderPlacement, 'data-cinder-label-visibility': _dataCinderLabelVisibility, 'data-cinder-menu-toggle-placement': _dataCinderMenuTogglePlacement, onclick: consumerOnClick, onkeydown: consumerOnKeyDown, ...rest } = $props();
|
|
14
14
|
const navigationItemSelector = '[data-cinder-navigation-item]';
|
|
15
|
+
const toggleFocusSelector = '.cinder-navigation-bar__menu-toggle button, .cinder-navigation-bar__menu-toggle [href], .cinder-navigation-bar__menu-toggle input, .cinder-navigation-bar__menu-toggle select, .cinder-navigation-bar__menu-toggle textarea, .cinder-navigation-bar__menu-toggle [tabindex]:not([tabindex="-1"])';
|
|
15
16
|
const isCollapsible = $derived(placement === 'top' && menuToggle !== undefined);
|
|
16
17
|
let isMobileLayout = $state(false);
|
|
17
18
|
const variant = $derived(placement === 'bottom'
|
|
@@ -95,15 +96,56 @@ function isEnabledNavigationItem(item) {
|
|
|
95
96
|
return item.getAttribute('aria-disabled') !== 'true' && !item.hasAttribute('disabled');
|
|
96
97
|
}
|
|
97
98
|
function getEventNavigationItem(event) {
|
|
98
|
-
if (!(event.target instanceof
|
|
99
|
+
if (!(event.target instanceof Element) || !itemsRegionElement)
|
|
99
100
|
return null;
|
|
100
101
|
const navigationItem = event.target.closest(navigationItemSelector);
|
|
101
102
|
if (!navigationItem || !itemsRegionElement.contains(navigationItem))
|
|
102
103
|
return null;
|
|
103
|
-
if (navigationItem !== event.target)
|
|
104
|
-
return null;
|
|
105
104
|
return navigationItem;
|
|
106
105
|
}
|
|
106
|
+
function isModifiedClick(event) {
|
|
107
|
+
return event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
108
|
+
}
|
|
109
|
+
function opensOutsideCurrentPage(item) {
|
|
110
|
+
if (!(item instanceof HTMLAnchorElement))
|
|
111
|
+
return false;
|
|
112
|
+
const target = item.getAttribute('target');
|
|
113
|
+
return (item.hasAttribute('download') ||
|
|
114
|
+
(target !== null && target.trim() !== '' && target.trim().toLowerCase() !== '_self'));
|
|
115
|
+
}
|
|
116
|
+
function canCloseAfterItemActivation(item, event) {
|
|
117
|
+
return (isCollapsible &&
|
|
118
|
+
isMobileLayout &&
|
|
119
|
+
mobileMenuOpen &&
|
|
120
|
+
isEnabledNavigationItem(item) &&
|
|
121
|
+
!isModifiedClick(event) &&
|
|
122
|
+
!opensOutsideCurrentPage(item));
|
|
123
|
+
}
|
|
124
|
+
function moveFocusBeforeClosingItemsRegion() {
|
|
125
|
+
if (!browser || !itemsRegionElement)
|
|
126
|
+
return;
|
|
127
|
+
const activeElement = document.activeElement;
|
|
128
|
+
if (activeElement instanceof Element && itemsRegionElement.contains(activeElement)) {
|
|
129
|
+
focusMenuToggle();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function focusMenuToggle() {
|
|
133
|
+
const focusTarget = toggleElement ?? navigationBarElement?.querySelector(toggleFocusSelector);
|
|
134
|
+
focusTarget?.focus();
|
|
135
|
+
}
|
|
136
|
+
function handleClick(event) {
|
|
137
|
+
if (consumerOnClick) {
|
|
138
|
+
const currentTarget = event.currentTarget instanceof HTMLElement ? event.currentTarget : navigationBarElement;
|
|
139
|
+
consumerOnClick.call(currentTarget, event);
|
|
140
|
+
}
|
|
141
|
+
if (event.defaultPrevented)
|
|
142
|
+
return;
|
|
143
|
+
const navigationItem = getEventNavigationItem(event);
|
|
144
|
+
if (!navigationItem || !canCloseAfterItemActivation(navigationItem, event))
|
|
145
|
+
return;
|
|
146
|
+
moveFocusBeforeClosingItemsRegion();
|
|
147
|
+
mobileMenuOpen = false;
|
|
148
|
+
}
|
|
107
149
|
function focusAdjacentNavigationItem(currentItem, direction) {
|
|
108
150
|
const items = getNavigationItems();
|
|
109
151
|
if (items.length === 0)
|
|
@@ -129,12 +171,11 @@ function handleKeyDown(event) {
|
|
|
129
171
|
return;
|
|
130
172
|
if (event.key === 'Escape' && isCollapsible && isMobileLayout && mobileMenuOpen) {
|
|
131
173
|
mobileMenuOpen = false;
|
|
132
|
-
|
|
133
|
-
toggleElement?.focus();
|
|
174
|
+
focusMenuToggle();
|
|
134
175
|
return;
|
|
135
176
|
}
|
|
136
177
|
const navigationItem = getEventNavigationItem(event);
|
|
137
|
-
if (!navigationItem)
|
|
178
|
+
if (!navigationItem || navigationItem !== event.target)
|
|
138
179
|
return;
|
|
139
180
|
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
|
140
181
|
event.preventDefault();
|
|
@@ -159,6 +200,7 @@ function handleKeyDown(event) {
|
|
|
159
200
|
data-cinder-placement={placement}
|
|
160
201
|
data-cinder-label-visibility={showLabels}
|
|
161
202
|
data-cinder-menu-toggle-placement={menuTogglePlacement}
|
|
203
|
+
onclick={handleClick}
|
|
162
204
|
onkeydown={handleKeyDown}
|
|
163
205
|
>
|
|
164
206
|
{#if isCollapsible && menuToggle && menuTogglePlacement === 'before-brand'}
|
|
@@ -24,9 +24,11 @@ const navigationLabel = $derived(`${validatedLabel} navigation`);
|
|
|
24
24
|
// on Firefox and Safari.
|
|
25
25
|
// Keep the fallback explicit for SSR-contract test environments that resolve
|
|
26
26
|
// the client MediaQuery build while `window.matchMedia` is unavailable.
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const hasMatchMedia = typeof window !== 'undefined' && typeof window.matchMedia === 'function';
|
|
28
|
+
const usesSsrResponsiveFallback = !hasMatchMedia;
|
|
29
|
+
const mobile = hasMatchMedia
|
|
30
|
+
? new MediaQuery('(max-width: 47.99rem)', false)
|
|
31
|
+
: { current: false };
|
|
30
32
|
const context = {
|
|
31
33
|
get collapsed() {
|
|
32
34
|
return collapsed;
|
|
@@ -84,6 +86,7 @@ setSidebarContext(context);
|
|
|
84
86
|
class={classNames('cinder-sidebar', 'cinder-sidebar--desktop', className)}
|
|
85
87
|
aria-label={validatedLabel}
|
|
86
88
|
data-cinder-collapsed={collapsed ? '' : undefined}
|
|
89
|
+
data-cinder-ssr-mobile-fallback={usesSsrResponsiveFallback ? '' : undefined}
|
|
87
90
|
>
|
|
88
91
|
{@render sidebarContents(false)}
|
|
89
92
|
</aside>
|