@astryx-vue/lab 0.5.0 → 0.5.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/README.md CHANGED
@@ -31,6 +31,8 @@ Or pick single files: `@astryx-vue/lab/styles/stat.css`, `.../log-stream.css`, a
31
31
  | `ListInput` | Editable records with custom input columns, validation, and reordering. |
32
32
  | `MobileTokenizer` | Touch-friendly multi-select with search and creation in a bottom sheet. |
33
33
  | `TransferList` | Dual-panel selection with search, grouping, and reordering. |
34
+ | `ChatEmojiPicker` | Popover emoji grid with shortname filtering and arrow-key navigation. |
35
+ | `ChatReactionBar` | Emoji reaction pills under a message, with an optional add button. |
34
36
 
35
37
  ## Documentation
36
38
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,120 @@
1
1
  import { MaybeRef, VNodeChild } from "vue";
2
2
  import { FieldStatusInput, IconSize, PopoverAlignment, PopoverPlacement, SyntaxThemeDefinition, TokenLine } from "@astryx-vue/core";
3
+ //#region src/Chat/types.d.ts
4
+ interface ChatEmojiOption {
5
+ /** 表情字符,例如 "🎉"。 */
6
+ emoji: string;
7
+ /** 短名,用来过滤,也用来生成按钮的无障碍名,例如 "tada"。 */
8
+ name: string;
9
+ }
10
+ interface ChatEmojiPickerProps {
11
+ /**
12
+ * 网格里的表情,每行 8 个。
13
+ * @default DEFAULT_CHAT_EMOJIS
14
+ */
15
+ emojis?: readonly ChatEmojiOption[];
16
+ /**
17
+ * 弹出层对话框的无障碍名。
18
+ * 不传时用内置的 “Pick an emoji”。
19
+ */
20
+ label?: string;
21
+ /**
22
+ * 过滤框的占位符和隐藏标签。
23
+ * 不传时用 `@astryx.emojiPicker.searchLabel`。
24
+ */
25
+ searchLabel?: string;
26
+ }
27
+ interface ChatEmojiPickerEmits {
28
+ /** 选中的表情。弹出层随后关闭,过滤词清空。 */
29
+ select: [emoji: string];
30
+ }
31
+ interface ChatEmojiPickerSlots {
32
+ /** 触发元素,里面要有一个按钮。 */
33
+ default?: () => unknown;
34
+ }
35
+ interface ChatReaction {
36
+ /** 表情字符,例如 "🎉"。 */
37
+ emoji: string;
38
+ /** 用这个表情回应的人数。 */
39
+ count: number;
40
+ /**
41
+ * 当前用户是不是已经回应过。
42
+ * 为真时胶囊用强调色,并且 `aria-pressed="true"`。
43
+ * @default false
44
+ */
45
+ isSelected?: boolean;
46
+ /**
47
+ * 给人看的说明,同时作为提示和无障碍名,
48
+ * 例如 "Ana and Dana reacted with 🎉"。
49
+ * 不传时按数量生成 “N reaction(s) with …”。
50
+ */
51
+ label?: string;
52
+ }
53
+ interface ChatReactionBarProps {
54
+ /** 按显示顺序排列的回应。 */
55
+ reactions: readonly ChatReaction[];
56
+ /**
57
+ * 添加回应时,选择器里的表情。
58
+ * @default DEFAULT_CHAT_EMOJIS
59
+ */
60
+ emojis?: readonly ChatEmojiOption[];
61
+ /**
62
+ * 添加按钮和选择器对话框的无障碍名。
63
+ * 不传时用 `@astryx.comments.addReaction`。
64
+ */
65
+ addLabel?: string;
66
+ /**
67
+ * 这一组回应的无障碍名。
68
+ * 不传时用内置的 “Reactions”。
69
+ */
70
+ label?: string;
71
+ }
72
+ interface ChatReactionBarEmits {
73
+ /** 用户点了某个已有回应。 */
74
+ toggle: [emoji: string];
75
+ /**
76
+ * 用户从选择器里新加了一个表情。
77
+ * 只有监听了这个事件,末尾才会出现添加按钮。
78
+ */
79
+ add: [emoji: string];
80
+ }
81
+ //#endregion
82
+ //#region src/Chat/ChatEmojiPicker.vue.d.ts
83
+ type __VLS_Slots$7 = ChatEmojiPickerSlots;
84
+ declare const __VLS_base$7: import("vue").DefineComponent<ChatEmojiPickerProps, {
85
+ element: Readonly<import("vue").ShallowRef<HTMLDivElement | null>>;
86
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
87
+ select: (emoji: string) => any;
88
+ }, string, import("vue").PublicProps, Readonly<ChatEmojiPickerProps> & Readonly<{
89
+ onSelect?: ((emoji: string) => any) | undefined;
90
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
91
+ declare const __VLS_export$14: __VLS_WithSlots$7<typeof __VLS_base$7, __VLS_Slots$7>;
92
+ declare const _default: typeof __VLS_export$14;
93
+ type __VLS_WithSlots$7<T, S> = T & {
94
+ new (): {
95
+ $slots: S;
96
+ };
97
+ };
98
+ //#endregion
99
+ //#region src/Chat/ChatReactionBar.vue.d.ts
100
+ declare const __VLS_export$13: import("vue").DefineComponent<ChatReactionBarProps, {
101
+ element: Readonly<import("vue").ShallowRef<HTMLDivElement | null>>;
102
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
103
+ add: (emoji: string) => any;
104
+ toggle: (emoji: string) => any;
105
+ }, string, import("vue").PublicProps, Readonly<ChatReactionBarProps> & Readonly<{
106
+ onAdd?: ((emoji: string) => any) | undefined;
107
+ onToggle?: ((emoji: string) => any) | undefined;
108
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
109
+ declare const _default$1: typeof __VLS_export$13;
110
+ //#endregion
111
+ //#region src/Chat/emojis.d.ts
112
+ /**
113
+ * 两行常用回应。调用方可以用 `emojis` 换成自己的一组。
114
+ * 内容和原版 `DEFAULT_CHAT_EMOJIS` 一致。
115
+ */
116
+ export declare const DEFAULT_CHAT_EMOJIS: readonly ChatEmojiOption[];
117
+ //#endregion
3
118
  //#region src/CircularProgress/types.d.ts
4
119
  /** Variants a theme can extend through declaration merging in TypeScript. */
5
120
  interface CircularProgressVariantMap {
@@ -68,17 +183,17 @@ type __VLS_Slots$6 = {} & {
68
183
  };
69
184
  declare const __VLS_base$6: import("vue").DefineComponent<CircularProgressProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<CircularProgressProps> & Readonly<{}>, {
70
185
  value: number;
71
- size: CircularProgressSize;
72
186
  max: number;
73
187
  isLabelHidden: boolean;
74
188
  hasValueLabel: boolean;
75
189
  formatValueLabel: (value: number, max: number) => string;
190
+ size: CircularProgressSize;
76
191
  variant: keyof CircularProgressVariantMap;
77
192
  isIndeterminate: boolean;
78
193
  isDisabled: boolean;
79
194
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
80
195
  declare const __VLS_export$12: __VLS_WithSlots$6<typeof __VLS_base$6, __VLS_Slots$6>;
81
- declare const _default: typeof __VLS_export$12;
196
+ declare const _default$2: typeof __VLS_export$12;
82
197
  type __VLS_WithSlots$6<T, S> = T & {
83
198
  new (): {
84
199
  $slots: S;
@@ -116,7 +231,7 @@ declare const __VLS_export$11: import("vue").DefineComponent<CodeEditorProps, {}
116
231
  language: string;
117
232
  escapeHint: string;
118
233
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
119
- declare const _default$1: typeof __VLS_export$11;
234
+ declare const _default$3: typeof __VLS_export$11;
120
235
  //#endregion
121
236
  //#region src/DiffViewer/diffTypes.d.ts
122
237
  /**
@@ -347,7 +462,7 @@ declare const __VLS_base$5: import("vue").DefineComponent<DiffViewerProps, {}, {
347
462
  renderLineAnnotation: (ref: DiffViewerLineRef) => import("vue").VNodeChild;
348
463
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
349
464
  declare const __VLS_export$10: __VLS_WithSlots$5<typeof __VLS_base$5, __VLS_Slots$5>;
350
- declare const _default$2: typeof __VLS_export$10;
465
+ declare const _default$4: typeof __VLS_export$10;
351
466
  type __VLS_WithSlots$5<T, S> = T & {
352
467
  new (): {
353
468
  $slots: S;
@@ -432,7 +547,7 @@ declare const __VLS_base$4: import("vue").DefineComponent<InfoTipProps, {}, {},
432
547
  content: string;
433
548
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
434
549
  declare const __VLS_export$9: __VLS_WithSlots$4<typeof __VLS_base$4, __VLS_Slots$4>;
435
- declare const _default$3: typeof __VLS_export$9;
550
+ declare const _default$5: typeof __VLS_export$9;
436
551
  type __VLS_WithSlots$4<T, S> = T & {
437
552
  new (): {
438
553
  $slots: S;
@@ -562,7 +677,7 @@ declare const __VLS_export$8: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_
562
677
  }>) => import("vue").VNode & {
563
678
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
564
679
  };
565
- declare const _default$4: typeof __VLS_export$8;
680
+ declare const _default$6: typeof __VLS_export$8;
566
681
  type __VLS_PrettifyLocal$3<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
567
682
  //#endregion
568
683
  //#region src/LogStream/types.d.ts
@@ -648,7 +763,7 @@ declare const __VLS_base$3: import("vue").DefineComponent<__VLS_PublicProps, {},
648
763
  hasTimestamps: boolean;
649
764
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
650
765
  declare const __VLS_export$7: __VLS_WithSlots$3<typeof __VLS_base$3, __VLS_Slots$3>;
651
- declare const _default$5: typeof __VLS_export$7;
766
+ declare const _default$7: typeof __VLS_export$7;
652
767
  type __VLS_WithSlots$3<T, S> = T & {
653
768
  new (): {
654
769
  $slots: S;
@@ -739,7 +854,7 @@ declare const __VLS_export$6: <T extends SearchableItem>(__VLS_props: NonNullabl
739
854
  }>) => import("vue").VNode & {
740
855
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
741
856
  };
742
- declare const _default$6: typeof __VLS_export$6;
857
+ declare const _default$8: typeof __VLS_export$6;
743
858
  type __VLS_PrettifyLocal$2<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
744
859
  //#endregion
745
860
  //#region src/Stat/types.d.ts
@@ -786,12 +901,12 @@ type __VLS_Slots$2 = {} & {
786
901
  };
787
902
  declare const __VLS_base$2: import("vue").DefineComponent<StatProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<StatProps> & Readonly<{}>, {
788
903
  value: string;
904
+ size: StatSize;
789
905
  delta: StatDelta;
790
906
  description: string;
791
- size: StatSize;
792
907
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
793
908
  declare const __VLS_export$5: __VLS_WithSlots$2<typeof __VLS_base$2, __VLS_Slots$2>;
794
- declare const _default$8: typeof __VLS_export$5;
909
+ declare const _default$10: typeof __VLS_export$5;
795
910
  type __VLS_WithSlots$2<T, S> = T & {
796
911
  new (): {
797
912
  $slots: S;
@@ -939,7 +1054,7 @@ declare const __VLS_export$4: import("vue").DefineComponent<SVGIconProps, {}, {}
939
1054
  variation: SVGIconVariation;
940
1055
  color: SVGIconColor;
941
1056
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
942
- declare const _default$7: typeof __VLS_export$4;
1057
+ declare const _default$9: typeof __VLS_export$4;
943
1058
  //#endregion
944
1059
  //#region src/SVGIcon/types-xif.d.ts
945
1060
  /**
@@ -1123,7 +1238,7 @@ declare const __VLS_base$1: import("vue").DefineComponent<TourProps, {}, {}, {},
1123
1238
  isStepCountShown: boolean;
1124
1239
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
1125
1240
  declare const __VLS_export$3: __VLS_WithSlots$1<typeof __VLS_base$1, __VLS_Slots$1>;
1126
- declare const _default$9: typeof __VLS_export$3;
1241
+ declare const _default$11: typeof __VLS_export$3;
1127
1242
  type __VLS_WithSlots$1<T, S> = T & {
1128
1243
  new (): {
1129
1244
  $slots: S;
@@ -1134,7 +1249,7 @@ type __VLS_WithSlots$1<T, S> = T & {
1134
1249
  type __VLS_Slots = TourStepSlots;
1135
1250
  declare const __VLS_base: any;
1136
1251
  declare const __VLS_export$2: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
1137
- declare const _default$10: typeof __VLS_export$2;
1252
+ declare const _default$12: typeof __VLS_export$2;
1138
1253
  type __VLS_WithSlots<T, S> = T & {
1139
1254
  new (): {
1140
1255
  $slots: S;
@@ -1236,7 +1351,7 @@ declare const __VLS_export$1: <T extends string>(__VLS_props: NonNullable<Awaite
1236
1351
  }>) => import("vue").VNode & {
1237
1352
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
1238
1353
  };
1239
- declare const _default$11: typeof __VLS_export$1;
1354
+ declare const _default$13: typeof __VLS_export$1;
1240
1355
  type __VLS_PrettifyLocal$1<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
1241
1356
  //#endregion
1242
1357
  //#region src/TransferList/TransferListSelector.vue.d.ts
@@ -1292,7 +1407,7 @@ declare const __VLS_export: <T extends string>(__VLS_props: NonNullable<Awaited<
1292
1407
  }>) => import("vue").VNode & {
1293
1408
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
1294
1409
  };
1295
- declare const _default$12: typeof __VLS_export;
1410
+ declare const _default$14: typeof __VLS_export;
1296
1411
  type __VLS_PrettifyLocal<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
1297
1412
  //#endregion
1298
- export { _default as CircularProgress, type CircularProgressProps, type CircularProgressSize, type CircularProgressVariant, type CircularProgressVariantMap, _default$1 as CodeEditor, type CodeEditorEmits, type CodeEditorProps, type CreateDiffFileOptions, _default$2 as DiffViewer, type DiffViewerChangeIndicator, type DiffViewerEmits, type DiffViewerFile, type DiffViewerFileStatus, type DiffViewerHunk, type DiffViewerInlineHighlight, type DiffViewerLine, type DiffViewerLineKind, type DiffViewerLineRef, type DiffViewerProps, type DiffViewerSide, type DiffViewerSlots, type DiffViewerViewMode, type IconShape, type IconShapeRole, _default$3 as InfoTip, type InfoTipProps, type InfoTipSize, type InlineDiffGranularity, type InlineDiffResult, type InlineRange, _default$4 as ListInput, type ListInputChange, type ListInputColumn, type ListInputColumnWidth, type ListInputEmits, type ListInputProps, type ListInputRenderContext, type ListInputValueContext, type LogEntry, _default$5 as LogStream, type LogStreamEmits, type LogStreamLevel, type LogStreamProps, _default$6 as MobileTokenizer, type MobileTokenizerChange, type MobileTokenizerEmits, type MobileTokenizerProps, type PanelGroup, type PanelRow, type PathPersonality, _default$7 as SVGIcon, type SVGIconColor, type SVGIconDef, type SVGIconProps, type SVGIconSize, type SVGIconVariation, type SearchSource, type SearchableItem, _default$8 as Stat, type StatDelta, type StatDeltaDirection, type StatDeltaSentiment, type StatProps, type StatSize, _default$9 as Tour, type TourDismissSource, type TourEmits, type TourProps, type TourSlots, _default$10 as TourStep, type TourStepProps, type TourStepSlots, _default$11 as TransferList, type TransferListEmits, type TransferListOption, type TransferListProps, _default$12 as TransferListSelector, type TransferListSlots, type UseTourReturn, type XIFAnimate, type XIFIcon, type XIFPath, type XIFPersonality, type XIFSlot };
1413
+ export { type ChatEmojiOption, _default as ChatEmojiPicker, type ChatEmojiPickerEmits, type ChatEmojiPickerProps, type ChatEmojiPickerSlots, type ChatReaction, _default$1 as ChatReactionBar, type ChatReactionBarEmits, type ChatReactionBarProps, _default$2 as CircularProgress, type CircularProgressProps, type CircularProgressSize, type CircularProgressVariant, type CircularProgressVariantMap, _default$3 as CodeEditor, type CodeEditorEmits, type CodeEditorProps, type CreateDiffFileOptions, _default$4 as DiffViewer, type DiffViewerChangeIndicator, type DiffViewerEmits, type DiffViewerFile, type DiffViewerFileStatus, type DiffViewerHunk, type DiffViewerInlineHighlight, type DiffViewerLine, type DiffViewerLineKind, type DiffViewerLineRef, type DiffViewerProps, type DiffViewerSide, type DiffViewerSlots, type DiffViewerViewMode, type IconShape, type IconShapeRole, _default$5 as InfoTip, type InfoTipProps, type InfoTipSize, type InlineDiffGranularity, type InlineDiffResult, type InlineRange, _default$6 as ListInput, type ListInputChange, type ListInputColumn, type ListInputColumnWidth, type ListInputEmits, type ListInputProps, type ListInputRenderContext, type ListInputValueContext, type LogEntry, _default$7 as LogStream, type LogStreamEmits, type LogStreamLevel, type LogStreamProps, _default$8 as MobileTokenizer, type MobileTokenizerChange, type MobileTokenizerEmits, type MobileTokenizerProps, type PanelGroup, type PanelRow, type PathPersonality, _default$9 as SVGIcon, type SVGIconColor, type SVGIconDef, type SVGIconProps, type SVGIconSize, type SVGIconVariation, type SearchSource, type SearchableItem, _default$10 as Stat, type StatDelta, type StatDeltaDirection, type StatDeltaSentiment, type StatProps, type StatSize, _default$11 as Tour, type TourDismissSource, type TourEmits, type TourProps, type TourSlots, _default$12 as TourStep, type TourStepProps, type TourStepSlots, _default$13 as TransferList, type TransferListEmits, type TransferListOption, type TransferListProps, _default$14 as TransferListSelector, type TransferListSlots, type UseTourReturn, type XIFAnimate, type XIFIcon, type XIFPath, type XIFPersonality, type XIFSlot };
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, getCurrentInstance, guardReactiveProps, h, inject, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onBeforeUnmount, onMounted, onScopeDispose, openBlock, provide, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, toValue, unref, useAttrs, useId, useModel, useSlots, useTemplateRef, watch, withCtx } from "vue";
2
+ import { AlertDialog, BottomSheet, Button, CheckboxIndicator, ComplexSelector, EmptyState, Field, FieldStatus, HStack, Heading, Icon, IconButton, Item, List, Popover, SYNC_TOKENIZE_THRESHOLD, SyntaxTheme, Text, TextInput, Token, Tooltip, VStack, VisuallyHidden, applyHighlightRangesFlat, tokenize, tokenizeAsync, useAnnounce, useAstryxMessages, useGridFocus, useScrollableArea, useTranslator } from "@astryx-vue/core";
3
+ import "../styles/chat-emoji-picker.css";
4
+ import "../styles/chat-reaction-bar.css";
2
5
  import "../styles/circular-progress.css";
3
- import { AlertDialog, BottomSheet, Button, CheckboxIndicator, ComplexSelector, EmptyState, Field, FieldStatus, HStack, Heading, Icon, IconButton, Item, List, Popover, SYNC_TOKENIZE_THRESHOLD, SyntaxTheme, Text, TextInput, Token, Tooltip, VStack, VisuallyHidden, applyHighlightRangesFlat, tokenize, tokenizeAsync, useAnnounce, useScrollableArea, useTranslator } from "@astryx-vue/core";
4
6
  import "../styles/code-editor.css";
5
7
  import "../styles/diff-viewer.css";
6
8
  import "../styles/info-tip.css";
@@ -12,6 +14,289 @@ import "../styles/svg-icon.css";
12
14
  import "../styles/tour.css";
13
15
  import "../styles/transfer-list.css";
14
16
  import "../styles/transfer-list-selector.css";
17
+ //#region src/Chat/emojis.ts
18
+ /**
19
+ * 两行常用回应。调用方可以用 `emojis` 换成自己的一组。
20
+ * 内容和原版 `DEFAULT_CHAT_EMOJIS` 一致。
21
+ */
22
+ const DEFAULT_CHAT_EMOJIS = [
23
+ {
24
+ emoji: "👍",
25
+ name: "thumbs up"
26
+ },
27
+ {
28
+ emoji: "❤️",
29
+ name: "heart"
30
+ },
31
+ {
32
+ emoji: "😂",
33
+ name: "joy"
34
+ },
35
+ {
36
+ emoji: "🎉",
37
+ name: "tada"
38
+ },
39
+ {
40
+ emoji: "😮",
41
+ name: "wow"
42
+ },
43
+ {
44
+ emoji: "😢",
45
+ name: "cry"
46
+ },
47
+ {
48
+ emoji: "🔥",
49
+ name: "fire"
50
+ },
51
+ {
52
+ emoji: "👀",
53
+ name: "eyes"
54
+ },
55
+ {
56
+ emoji: "✅",
57
+ name: "check"
58
+ },
59
+ {
60
+ emoji: "🙏",
61
+ name: "pray"
62
+ },
63
+ {
64
+ emoji: "💯",
65
+ name: "hundred"
66
+ },
67
+ {
68
+ emoji: "🚀",
69
+ name: "rocket"
70
+ },
71
+ {
72
+ emoji: "😍",
73
+ name: "heart eyes"
74
+ },
75
+ {
76
+ emoji: "🤔",
77
+ name: "thinking"
78
+ },
79
+ {
80
+ emoji: "👋",
81
+ name: "wave"
82
+ },
83
+ {
84
+ emoji: "⭐",
85
+ name: "star"
86
+ }
87
+ ];
88
+ //#endregion
89
+ //#region src/Chat/filterEmojis.ts
90
+ /** 短名包含查询,或者查询本身就是那个表情字符。大小写不敏感,首尾空白不算。 */
91
+ function filterEmojis(emojis, query) {
92
+ const trimmed = query.trim().toLowerCase();
93
+ if (trimmed === "") return [...emojis];
94
+ return emojis.filter((option) => option.name.toLowerCase().includes(trimmed) || option.emoji === trimmed);
95
+ }
96
+ //#endregion
97
+ //#region src/Chat/ChatEmojiPicker.vue
98
+ const _hoisted_1$18 = {
99
+ key: 0,
100
+ class: "astryx-chat-emoji-picker__empty"
101
+ };
102
+ const _hoisted_2$16 = ["aria-label"];
103
+ const _hoisted_3$14 = [
104
+ "data-emoji",
105
+ "aria-label",
106
+ "onClick"
107
+ ];
108
+ const _hoisted_4$13 = { "aria-hidden": "true" };
109
+ const _sfc_main = /*@__PURE__*/ defineComponent({
110
+ name: "AstryxChatEmojiPicker",
111
+ inheritAttrs: false,
112
+ __name: "ChatEmojiPicker",
113
+ props: {
114
+ emojis: {},
115
+ label: {},
116
+ searchLabel: {}
117
+ },
118
+ emits: ["select"],
119
+ setup(__props, { expose: __expose, emit: __emit }) {
120
+ const props = __props;
121
+ const emit = __emit;
122
+ const { t } = useTranslator();
123
+ const messages = useAstryxMessages();
124
+ const query = ref("");
125
+ const isOpen = ref(false);
126
+ const panel = useTemplateRef("panel");
127
+ const { gridRef, handleKeyDown } = useGridFocus({ columns: 8 });
128
+ function setGrid(element) {
129
+ gridRef.value = element instanceof HTMLElement ? element : null;
130
+ }
131
+ const options = computed(() => props.emojis ?? DEFAULT_CHAT_EMOJIS);
132
+ const visible = computed(() => filterEmojis(options.value, query.value));
133
+ const dialogLabel = computed(() => props.label ?? messages.value.emojiPicker.pickLabel);
134
+ const searchText = computed(() => props.searchLabel ?? t("@astryx.emojiPicker.searchLabel"));
135
+ const gridLabel = computed(() => t("@astryx.emojiPicker.label"));
136
+ const emptyText = computed(() => t("@astryx.emojiPicker.noResults", { query: query.value.trim() }));
137
+ function onOpenChange(open) {
138
+ isOpen.value = open;
139
+ if (!open) query.value = "";
140
+ }
141
+ function pick(emoji) {
142
+ emit("select", emoji);
143
+ query.value = "";
144
+ isOpen.value = false;
145
+ }
146
+ __expose({ element: panel });
147
+ return (_ctx, _cache) => {
148
+ return openBlock(), createBlock(unref(Popover), {
149
+ "is-open": isOpen.value,
150
+ label: dialogLabel.value,
151
+ placement: "below",
152
+ alignment: "start",
153
+ padding: 2,
154
+ width: 320,
155
+ onOpenChange
156
+ }, {
157
+ content: withCtx(() => [createElementVNode("div", mergeProps({
158
+ ref_key: "panel",
159
+ ref: panel,
160
+ class: "astryx-chat-emoji-picker"
161
+ }, _ctx.$attrs), [createVNode(unref(TextInput), {
162
+ modelValue: query.value,
163
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
164
+ class: "astryx-chat-emoji-picker__search",
165
+ label: searchText.value,
166
+ "is-label-hidden": "",
167
+ size: "sm",
168
+ placeholder: searchText.value,
169
+ "has-clear": "",
170
+ width: "100%"
171
+ }, null, 8, [
172
+ "modelValue",
173
+ "label",
174
+ "placeholder"
175
+ ]), visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_1$18, toDisplayString(emptyText.value), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" eslint-disable-next-line vue-a11y/no-static-element-interactions -- 焦点在格子按钮上,方向键冒泡到这层再按网格移动。 "), createElementVNode("div", {
176
+ ref: setGrid,
177
+ class: "astryx-chat-emoji-picker__grid",
178
+ role: "group",
179
+ "aria-label": gridLabel.value,
180
+ onKeydown: _cache[1] || (_cache[1] = (...args) => unref(handleKeyDown) && unref(handleKeyDown)(...args))
181
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(visible.value, (option) => {
182
+ return openBlock(), createElementBlock("button", {
183
+ key: option.emoji,
184
+ type: "button",
185
+ class: "astryx-chat-emoji-picker__cell",
186
+ "data-emoji": option.emoji,
187
+ "aria-label": unref(messages).emojiPicker.reactWith(option.name),
188
+ onClick: ($event) => pick(option.emoji)
189
+ }, [createElementVNode("span", _hoisted_4$13, toDisplayString(option.emoji), 1)], 8, _hoisted_3$14);
190
+ }), 128))], 40, _hoisted_2$16)], 2112))], 16)]),
191
+ default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
192
+ _: 3
193
+ }, 8, ["is-open", "label"]);
194
+ };
195
+ }
196
+ });
197
+ //#endregion
198
+ //#region src/Chat/ChatReactionBar.vue
199
+ const _hoisted_1$17 = ["aria-label"];
200
+ const _hoisted_2$15 = [
201
+ "data-selected",
202
+ "aria-pressed",
203
+ "aria-label",
204
+ "onClick"
205
+ ];
206
+ const _hoisted_3$13 = {
207
+ class: "astryx-chat-reaction-bar__emoji",
208
+ "aria-hidden": "true"
209
+ };
210
+ const _hoisted_4$12 = { class: "astryx-chat-reaction-bar__count" };
211
+ const _hoisted_5$11 = [
212
+ "data-selected",
213
+ "aria-pressed",
214
+ "aria-label",
215
+ "onClick"
216
+ ];
217
+ const _hoisted_6$9 = {
218
+ class: "astryx-chat-reaction-bar__emoji",
219
+ "aria-hidden": "true"
220
+ };
221
+ const _hoisted_7$7 = { class: "astryx-chat-reaction-bar__count" };
222
+ const _hoisted_8$5 = ["aria-label"];
223
+ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
224
+ name: "AstryxChatReactionBar",
225
+ inheritAttrs: false,
226
+ __name: "ChatReactionBar",
227
+ props: {
228
+ reactions: {},
229
+ emojis: {},
230
+ addLabel: {},
231
+ label: {}
232
+ },
233
+ emits: ["toggle", "add"],
234
+ setup(__props, { expose: __expose }) {
235
+ const props = __props;
236
+ const instance = getCurrentInstance();
237
+ const { t } = useTranslator();
238
+ const messages = useAstryxMessages();
239
+ const root = useTemplateRef("root");
240
+ const groupLabel = computed(() => props.label ?? messages.value.comments.reactionsLabel);
241
+ const addLabel = computed(() => props.addLabel ?? t("@astryx.comments.addReaction"));
242
+ const hasAdd = computed(() => {
243
+ const vnodeProps = instance?.vnode.props;
244
+ return vnodeProps?.onAdd != null || vnodeProps?.onAddOnce != null;
245
+ });
246
+ function pillLabel(reaction) {
247
+ return reaction.label ?? messages.value.comments.reactionWith(reaction.count, reaction.emoji);
248
+ }
249
+ __expose({ element: root });
250
+ return (_ctx, _cache) => {
251
+ return openBlock(), createElementBlock("div", mergeProps({
252
+ ref_key: "root",
253
+ ref: root,
254
+ class: "astryx-chat-reaction-bar",
255
+ role: "group",
256
+ "aria-label": groupLabel.value
257
+ }, _ctx.$attrs), [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.reactions, (reaction) => {
258
+ return openBlock(), createElementBlock(Fragment, { key: reaction.emoji }, [reaction.label != null ? (openBlock(), createBlock(unref(Tooltip), {
259
+ key: 0,
260
+ content: reaction.label
261
+ }, {
262
+ default: withCtx(() => [createElementVNode("button", {
263
+ type: "button",
264
+ class: "astryx-chat-reaction-bar__pill",
265
+ "data-selected": reaction.isSelected === true || void 0,
266
+ "aria-pressed": reaction.isSelected === true,
267
+ "aria-label": pillLabel(reaction),
268
+ onClick: ($event) => _ctx.$emit("toggle", reaction.emoji)
269
+ }, [createElementVNode("span", _hoisted_3$13, toDisplayString(reaction.emoji), 1), createElementVNode("span", _hoisted_4$12, toDisplayString(reaction.count), 1)], 8, _hoisted_2$15)]),
270
+ _: 2
271
+ }, 1032, ["content"])) : (openBlock(), createElementBlock("button", {
272
+ key: 1,
273
+ type: "button",
274
+ class: "astryx-chat-reaction-bar__pill",
275
+ "data-selected": reaction.isSelected === true || void 0,
276
+ "aria-pressed": reaction.isSelected === true,
277
+ "aria-label": pillLabel(reaction),
278
+ onClick: ($event) => _ctx.$emit("toggle", reaction.emoji)
279
+ }, [createElementVNode("span", _hoisted_6$9, toDisplayString(reaction.emoji), 1), createElementVNode("span", _hoisted_7$7, toDisplayString(reaction.count), 1)], 8, _hoisted_5$11))], 64);
280
+ }), 128)), hasAdd.value ? (openBlock(), createBlock(_sfc_main, {
281
+ key: 0,
282
+ emojis: __props.emojis,
283
+ label: addLabel.value,
284
+ onSelect: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("add", $event))
285
+ }, {
286
+ default: withCtx(() => [createVNode(unref(Tooltip), { content: addLabel.value }, {
287
+ default: withCtx(() => [createElementVNode("button", {
288
+ type: "button",
289
+ class: "astryx-chat-reaction-bar__add",
290
+ "aria-label": addLabel.value
291
+ }, " + ", 8, _hoisted_8$5)]),
292
+ _: 1
293
+ }, 8, ["content"])]),
294
+ _: 1
295
+ }, 8, ["emojis", "label"])) : createCommentVNode("v-if", true)], 16, _hoisted_1$17);
296
+ };
297
+ }
298
+ });
299
+ //#endregion
15
300
  //#region src/CircularProgress/types.ts
16
301
  /** Ring geometry per size: outer diameter and stroke width in px. */
17
302
  const SIZE_CONFIG = {
@@ -72,7 +357,7 @@ const _hoisted_7$6 = {
72
357
  key: 0,
73
358
  class: "astryx-circular-progress__center"
74
359
  };
75
- const _sfc_main = /*@__PURE__*/ defineComponent({
360
+ const _sfc_main$2 = /*@__PURE__*/ defineComponent({
76
361
  name: "AstryxCircularProgress",
77
362
  inheritAttrs: false,
78
363
  __name: "CircularProgress",
@@ -267,7 +552,7 @@ const _hoisted_5$9 = [
267
552
  "aria-readonly",
268
553
  "aria-describedby"
269
554
  ];
270
- const _sfc_main$1 = /*@__PURE__*/ defineComponent({
555
+ const _sfc_main$3 = /*@__PURE__*/ defineComponent({
271
556
  name: "AstryxCodeEditor",
272
557
  __name: "CodeEditor",
273
558
  props: {
@@ -800,7 +1085,7 @@ const _hoisted_47 = {
800
1085
  key: 0,
801
1086
  class: "astryx-diff-viewer__annotation-content"
802
1087
  };
803
- const _sfc_main$17 = /*@__PURE__*/ defineComponent({
1088
+ const _sfc_main$19 = /*@__PURE__*/ defineComponent({
804
1089
  name: "AstryxDiffViewerTable",
805
1090
  __name: "DiffViewerTable",
806
1091
  props: {
@@ -1531,7 +1816,7 @@ const _hoisted_11$1 = {
1531
1816
  class: "astryx-diff-viewer__message"
1532
1817
  };
1533
1818
  const _hoisted_12 = ["aria-label"];
1534
- const _sfc_main$2 = /*@__PURE__*/ defineComponent({
1819
+ const _sfc_main$4 = /*@__PURE__*/ defineComponent({
1535
1820
  name: "AstryxDiffViewer",
1536
1821
  inheritAttrs: false,
1537
1822
  __name: "DiffViewer",
@@ -1720,7 +2005,7 @@ const _sfc_main$2 = /*@__PURE__*/ defineComponent({
1720
2005
  }), [createElementVNode("div", {
1721
2006
  ref: unref(scroll).content,
1722
2007
  class: "astryx-diff-viewer__content"
1723
- }, [createVNode(_sfc_main$17, {
2008
+ }, [createVNode(_sfc_main$19, {
1724
2009
  "view-mode": __props.viewMode,
1725
2010
  "unified-rows": unifiedRows.value,
1726
2011
  "split-rows": splitRows.value,
@@ -2042,7 +2327,7 @@ function parseUnifiedDiff(patch) {
2042
2327
  //#endregion
2043
2328
  //#region src/InfoTip/InfoTip.vue
2044
2329
  const _hoisted_1$12 = ["aria-label"];
2045
- const _sfc_main$3 = /*@__PURE__*/ defineComponent({
2330
+ const _sfc_main$5 = /*@__PURE__*/ defineComponent({
2046
2331
  name: "AstryxInfoTip",
2047
2332
  __name: "InfoTip",
2048
2333
  props: {
@@ -2169,7 +2454,7 @@ const _hoisted_7$3 = {
2169
2454
  key: 0,
2170
2455
  class: "astryx-list-input__control-cell astryx-list-input__control-cell--reorder"
2171
2456
  };
2172
- const _sfc_main$16 = /*@__PURE__*/ defineComponent({
2457
+ const _sfc_main$18 = /*@__PURE__*/ defineComponent({
2173
2458
  name: "AstryxListInputRow",
2174
2459
  __name: "ListInputRow",
2175
2460
  props: {
@@ -2615,7 +2900,7 @@ const _hoisted_5$5 = {
2615
2900
  class: "astryx-list-input__action-content"
2616
2901
  };
2617
2902
  const focusableFieldSelector = "[data-list-input-cell] input, [data-list-input-cell] select, [data-list-input-cell] textarea, [data-list-input-cell] button, [data-list-input-cell] [tabindex]:not([tabindex=\"-1\"])";
2618
- const _sfc_main$4 = /*@__PURE__*/ defineComponent({
2903
+ const _sfc_main$6 = /*@__PURE__*/ defineComponent({
2619
2904
  name: "AstryxListInput",
2620
2905
  inheritAttrs: false,
2621
2906
  __name: "ListInput",
@@ -2893,7 +3178,7 @@ const _sfc_main$4 = /*@__PURE__*/ defineComponent({
2893
3178
  description: unref(t)("@astryx.listInput.emptyDescription", { itemName: __props.itemName }),
2894
3179
  "is-compact": ""
2895
3180
  }, null, 8, ["title", "description"])])) : createCommentVNode("v-if", true), (openBlock(true), createElementBlock(Fragment, null, renderList(unref(reorder).displayValue.value, (item, index) => {
2896
- return openBlock(), createBlock(_sfc_main$16, {
3181
+ return openBlock(), createBlock(_sfc_main$18, {
2897
3182
  key: itemKeyOf(item),
2898
3183
  item,
2899
3184
  index,
@@ -3008,7 +3293,7 @@ const _hoisted_11 = {
3008
3293
  key: 0,
3009
3294
  class: "astryx-log-stream__detail"
3010
3295
  };
3011
- const _sfc_main$15 = /*@__PURE__*/ defineComponent({
3296
+ const _sfc_main$17 = /*@__PURE__*/ defineComponent({
3012
3297
  name: "AstryxLogStreamRow",
3013
3298
  __name: "LogStreamRow",
3014
3299
  props: {
@@ -3112,7 +3397,7 @@ function useLogFollow(options) {
3112
3397
  //#region src/LogStream/LogStream.vue
3113
3398
  const _hoisted_1$8 = ["data-variant"];
3114
3399
  const _hoisted_2$7 = ["aria-label", "aria-live"];
3115
- const _sfc_main$5 = /*@__PURE__*/ defineComponent({
3400
+ const _sfc_main$7 = /*@__PURE__*/ defineComponent({
3116
3401
  name: "AstryxLogStream",
3117
3402
  inheritAttrs: false,
3118
3403
  __name: "LogStream",
@@ -3178,7 +3463,7 @@ const _sfc_main$5 = /*@__PURE__*/ defineComponent({
3178
3463
  style: normalizeStyle(scrollerStyle.value),
3179
3464
  onScrollPassive: _cache[0] || (_cache[0] = (...args) => unref(handleScroll) && unref(handleScroll)(...args))
3180
3465
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.entries, (entry) => {
3181
- return renderSlot(_ctx.$slots, "entry", { entry }, () => [createVNode(_sfc_main$15, {
3466
+ return renderSlot(_ctx.$slots, "entry", { entry }, () => [createVNode(_sfc_main$17, {
3182
3467
  entry,
3183
3468
  "has-timestamps": __props.hasTimestamps,
3184
3469
  "has-source": hasSource.value,
@@ -3344,7 +3629,7 @@ const _hoisted_10$1 = {
3344
3629
  class: "astryx-mobile-tokenizer__footer"
3345
3630
  };
3346
3631
  const CREATABLE_ID_PREFIX = "__xds_create__";
3347
- const _sfc_main$6 = /*@__PURE__*/ defineComponent({
3632
+ const _sfc_main$8 = /*@__PURE__*/ defineComponent({
3348
3633
  name: "AstryxMobileTokenizer",
3349
3634
  inheritAttrs: false,
3350
3635
  __name: "MobileTokenizer",
@@ -3667,7 +3952,7 @@ const _hoisted_10 = {
3667
3952
  key: 1,
3668
3953
  class: "astryx-stat__media"
3669
3954
  };
3670
- const _sfc_main$8 = /*@__PURE__*/ defineComponent({
3955
+ const _sfc_main$10 = /*@__PURE__*/ defineComponent({
3671
3956
  name: "AstryxStat",
3672
3957
  inheritAttrs: false,
3673
3958
  __name: "Stat",
@@ -4524,7 +4809,7 @@ const _hoisted_6$1 = {
4524
4809
  key: 1,
4525
4810
  class: "astryx-svg-icon__layer astryx-svg-icon__layer--secondary-stroke"
4526
4811
  };
4527
- const _sfc_main$7 = /*@__PURE__*/ defineComponent({
4812
+ const _sfc_main$9 = /*@__PURE__*/ defineComponent({
4528
4813
  name: "AstryxSvgIcon",
4529
4814
  inheritAttrs: false,
4530
4815
  __name: "SVGIcon",
@@ -4760,7 +5045,7 @@ const xifExamples = [
4760
5045
  const TOUR_CONTEXT_KEY = Symbol("AstryxTour");
4761
5046
  //#endregion
4762
5047
  //#region src/Tour/Tour.vue
4763
- const _sfc_main$9 = /*@__PURE__*/ defineComponent({
5048
+ const _sfc_main$11 = /*@__PURE__*/ defineComponent({
4764
5049
  name: "AstryxTour",
4765
5050
  __name: "Tour",
4766
5051
  props: {
@@ -4824,7 +5109,7 @@ const _sfc_main$9 = /*@__PURE__*/ defineComponent({
4824
5109
  //#endregion
4825
5110
  //#region src/Tour/TourHighlight.vue
4826
5111
  const _hoisted_1$4 = ["data-testid"];
4827
- const _sfc_main$14 = /*@__PURE__*/ defineComponent({
5112
+ const _sfc_main$16 = /*@__PURE__*/ defineComponent({
4828
5113
  __name: "TourHighlight",
4829
5114
  props: {
4830
5115
  rect: {},
@@ -4868,7 +5153,7 @@ const _sfc_main$14 = /*@__PURE__*/ defineComponent({
4868
5153
  //#region src/Tour/TourStep.vue
4869
5154
  const _hoisted_1$3 = ["data-testid"];
4870
5155
  const _hoisted_2$3 = { key: 1 };
4871
- const _sfc_main$10 = /*@__PURE__*/ defineComponent({
5156
+ const _sfc_main$12 = /*@__PURE__*/ defineComponent({
4872
5157
  name: "AstryxTourStep",
4873
5158
  __name: "TourStep",
4874
5159
  props: {
@@ -4907,6 +5192,7 @@ const _sfc_main$10 = /*@__PURE__*/ defineComponent({
4907
5192
  };
4908
5193
  }
4909
5194
  function stopMeasuring() {
5195
+ if (typeof window === "undefined") return;
4910
5196
  window.removeEventListener("scroll", measure, true);
4911
5197
  window.removeEventListener("resize", measure);
4912
5198
  }
@@ -4935,7 +5221,7 @@ const _sfc_main$10 = /*@__PURE__*/ defineComponent({
4935
5221
  if (!open) tour?.onDismiss("close");
4936
5222
  }
4937
5223
  return (_ctx, _cache) => {
4938
- return unref(tour) && isActiveStep.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(_sfc_main$14, {
5224
+ return unref(tour) && isActiveStep.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(_sfc_main$16, {
4939
5225
  rect: rect.value,
4940
5226
  "has-backdrop": unref(tour).hasBackdrop.value,
4941
5227
  onBackdropClick: _cache[0] || (_cache[0] = ($event) => unref(tour).onDismiss("backdrop"))
@@ -5102,7 +5388,7 @@ const _hoisted_5 = {
5102
5388
  class: "astryx-transfer-list-panel__group-heading"
5103
5389
  };
5104
5390
  const _hoisted_6 = ["data-transfer-list-empty"];
5105
- const _sfc_main$13 = /*@__PURE__*/ defineComponent({
5391
+ const _sfc_main$15 = /*@__PURE__*/ defineComponent({
5106
5392
  name: "AstryxTransferListPanel",
5107
5393
  __name: "TransferListPanel",
5108
5394
  props: {
@@ -5574,7 +5860,7 @@ const _hoisted_3$1 = {
5574
5860
  class: "astryx-transfer-list__controls"
5575
5861
  };
5576
5862
  const _hoisted_4 = { class: "astryx-transfer-list-collection" };
5577
- const _sfc_main$11 = /*@__PURE__*/ defineComponent({
5863
+ const _sfc_main$13 = /*@__PURE__*/ defineComponent({
5578
5864
  name: "AstryxTransferList",
5579
5865
  inheritAttrs: false,
5580
5866
  __name: "TransferList",
@@ -5848,7 +6134,7 @@ const _sfc_main$11 = /*@__PURE__*/ defineComponent({
5848
6134
  default: withCtx(() => [createTextVNode(toDisplayString(unref(t)("@astryx.transferList.reorderInstructions")), 1)]),
5849
6135
  _: 1
5850
6136
  }),
5851
- createElementVNode("div", _hoisted_4, [createVNode(_sfc_main$13, {
6137
+ createElementVNode("div", _hoisted_4, [createVNode(_sfc_main$15, {
5852
6138
  side: "selected",
5853
6139
  "heading-id": selectedHeadingId,
5854
6140
  label: selectedLabel.value,
@@ -5884,7 +6170,7 @@ const _sfc_main$11 = /*@__PURE__*/ defineComponent({
5884
6170
  "dragging-value",
5885
6171
  "grabbed-value",
5886
6172
  "drop-target"
5887
- ]), createVNode(_sfc_main$13, {
6173
+ ]), createVNode(_sfc_main$15, {
5888
6174
  side: "available",
5889
6175
  "heading-id": availableHeadingId,
5890
6176
  label: availableLabel.value,
@@ -5939,7 +6225,7 @@ const _hoisted_3 = {
5939
6225
  class: "astryx-transfer-list-selector__footer"
5940
6226
  };
5941
6227
  const DEFAULT_SELECTOR_WIDTH = "min(41rem, calc(100vw - 32px))";
5942
- const _sfc_main$12 = /*@__PURE__*/ defineComponent({
6228
+ const _sfc_main$14 = /*@__PURE__*/ defineComponent({
5943
6229
  name: "AstryxTransferListSelector",
5944
6230
  __name: "TransferListSelector",
5945
6231
  props: {
@@ -6076,7 +6362,7 @@ const _sfc_main$12 = /*@__PURE__*/ defineComponent({
6076
6362
  }, [createElementVNode("fieldset", {
6077
6363
  class: "astryx-transfer-list-selector__fieldset",
6078
6364
  disabled: __props.isDisabled
6079
- }, [createVNode(_sfc_main$11, {
6365
+ }, [createVNode(_sfc_main$13, {
6080
6366
  label: __props.label,
6081
6367
  "is-label-hidden": "",
6082
6368
  options: __props.options,
@@ -6155,4 +6441,4 @@ const _sfc_main$12 = /*@__PURE__*/ defineComponent({
6155
6441
  }
6156
6442
  });
6157
6443
  //#endregion
6158
- export { _sfc_main as CircularProgress, _sfc_main$1 as CodeEditor, _sfc_main$2 as DiffViewer, _sfc_main$3 as InfoTip, _sfc_main$4 as ListInput, _sfc_main$5 as LogStream, _sfc_main$6 as MobileTokenizer, _sfc_main$7 as SVGIcon, _sfc_main$8 as Stat, _sfc_main$9 as Tour, _sfc_main$10 as TourStep, _sfc_main$11 as TransferList, _sfc_main$12 as TransferListSelector, addCurvature, adjustTension, applyPersonality, bellIcon, calendarIcon, checkIcon, createDiffFile, eyeIcon, folderIcon, heartIcon, homeIcon, lockIcon, mailIcon, menuIcon, parseUnifiedDiff, roundCorners, searchIcon, settingsIcon, shieldIcon, starIcon, starterIcons, useTour, xIcon, xifBell, xifBellOverride, xifCheck, xifExamples, xifFile, xifHome, xifShield, xifStar };
6444
+ export { _sfc_main as ChatEmojiPicker, _sfc_main$1 as ChatReactionBar, _sfc_main$2 as CircularProgress, _sfc_main$3 as CodeEditor, DEFAULT_CHAT_EMOJIS, _sfc_main$4 as DiffViewer, _sfc_main$5 as InfoTip, _sfc_main$6 as ListInput, _sfc_main$7 as LogStream, _sfc_main$8 as MobileTokenizer, _sfc_main$9 as SVGIcon, _sfc_main$10 as Stat, _sfc_main$11 as Tour, _sfc_main$12 as TourStep, _sfc_main$13 as TransferList, _sfc_main$14 as TransferListSelector, addCurvature, adjustTension, applyPersonality, bellIcon, calendarIcon, checkIcon, createDiffFile, eyeIcon, folderIcon, heartIcon, homeIcon, lockIcon, mailIcon, menuIcon, parseUnifiedDiff, roundCorners, searchIcon, settingsIcon, shieldIcon, starIcon, starterIcons, useTour, xIcon, xifBell, xifBellOverride, xifCheck, xifExamples, xifFile, xifHome, xifShield, xifStar };
package/lab.css CHANGED
@@ -11,3 +11,5 @@
11
11
  @import './styles/diff-viewer.css';
12
12
  @import './styles/tour.css';
13
13
  @import './styles/code-editor.css';
14
+ @import './styles/chat-emoji-picker.css';
15
+ @import './styles/chat-reaction-bar.css';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astryx-vue/lab",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "description": "Astryx lab components for Vue 3 — experimental components that may change. Ships only under the canary dist-tag.",
6
6
  "author": "ShenQingchuan",
7
7
  "license": "MIT",
@@ -53,7 +53,7 @@
53
53
  ],
54
54
  "peerDependencies": {
55
55
  "vue": "^3.5.0",
56
- "@astryx-vue/core": "^0.7.13"
56
+ "@astryx-vue/core": "^0.7.14"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node": "26.6.4",
@@ -64,7 +64,7 @@
64
64
  "unplugin-vue": "8.0.0",
65
65
  "vue": "3.5.43",
66
66
  "vue-tsc": "3.3.12",
67
- "@astryx-vue/core": "^0.7.13"
67
+ "@astryx-vue/core": "^0.7.14"
68
68
  },
69
69
  "scripts": {
70
70
  "build": "tsdown",
@@ -0,0 +1,80 @@
1
+ @layer astryx.reset, astryx.tokens, astryx.base, astryx.components, astryx.overrides;
2
+
3
+ @layer astryx.components {
4
+ .astryx-chat-emoji-picker {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: var(--astryx-spacing-2, 8px);
8
+ box-sizing: border-box;
9
+ min-width: 0;
10
+ }
11
+
12
+ .astryx-chat-emoji-picker__search {
13
+ width: 100%;
14
+ min-width: 0;
15
+ }
16
+
17
+ /* 8 列固定格子。方向键按这个几何走,不把格子拉成不等宽。 */
18
+ .astryx-chat-emoji-picker__grid {
19
+ display: grid;
20
+ grid-template-columns: repeat(8, 32px);
21
+ gap: var(--astryx-spacing-0-5, 2px);
22
+ justify-content: start;
23
+ }
24
+
25
+ .astryx-chat-emoji-picker__cell {
26
+ display: inline-flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ box-sizing: border-box;
30
+ width: 32px;
31
+ height: 32px;
32
+ margin: 0;
33
+ padding: 0;
34
+ border-style: none;
35
+ border-radius: var(--astryx-radius-inner, 0.375rem);
36
+ background-color: transparent;
37
+ color: inherit;
38
+ font-family: var(--astryx-font-family-body, inherit);
39
+ font-size: 18px;
40
+ line-height: var(--astryx-text-body-leading, 1.4286);
41
+ cursor: pointer;
42
+ transition-property: background-color;
43
+ transition-duration: var(--astryx-duration-fast, 125ms);
44
+ transition-timing-function: var(--astryx-ease-standard, cubic-bezier(0.24, 1, 0.4, 1));
45
+ }
46
+
47
+ /*
48
+ * 格子紧挨着,外扩的焦点环会压到旁边的格子,所以向内收 2px。
49
+ * 禁用和 aria-disabled 不给悬停底,指针也回到普通箭头(原版 a11y #5247 / #5335)。
50
+ */
51
+ @media (hover: hover) {
52
+ .astryx-chat-emoji-picker__cell:hover:where(:not(:disabled, [aria-disabled='true'])) {
53
+ background-color: var(--astryx-color-overlay-hover, light-dark(#0000000d, #ffffff0d));
54
+ }
55
+ }
56
+
57
+ .astryx-chat-emoji-picker__cell:is(:disabled, [aria-disabled='true']) {
58
+ cursor: default;
59
+ }
60
+
61
+ .astryx-chat-emoji-picker__cell:focus-visible {
62
+ outline: var(--astryx-focus-outline-width, 2px) var(--astryx-focus-outline-style, solid) var(--astryx-focus-outline-color, currentcolor);
63
+ outline-offset: -2px;
64
+ }
65
+
66
+ .astryx-chat-emoji-picker__empty {
67
+ padding-block: var(--astryx-spacing-2, 8px);
68
+ padding-inline: var(--astryx-spacing-1, 4px);
69
+ color: var(--astryx-color-text-secondary, light-dark(#6a6a6a, #9e9e9e));
70
+ font-family: var(--astryx-font-family-body, inherit);
71
+ font-size: var(--astryx-text-supporting-size, 0.75rem);
72
+ line-height: var(--astryx-text-supporting-leading, 1.6667);
73
+ }
74
+
75
+ @media (prefers-reduced-motion: reduce) {
76
+ .astryx-chat-emoji-picker__cell {
77
+ transition-duration: 0s;
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,96 @@
1
+ @layer astryx.reset, astryx.tokens, astryx.base, astryx.components, astryx.overrides;
2
+
3
+ @layer astryx.components {
4
+ .astryx-chat-reaction-bar {
5
+ display: flex;
6
+ flex-wrap: wrap;
7
+ align-items: center;
8
+ gap: var(--astryx-spacing-1, 4px);
9
+ }
10
+
11
+ .astryx-chat-reaction-bar__pill,
12
+ .astryx-chat-reaction-bar__add {
13
+ box-sizing: border-box;
14
+ margin: 0;
15
+ border-width: 1px;
16
+ border-style: solid;
17
+ border-color: transparent;
18
+ background-color: var(--astryx-color-background-muted, light-dark(#f1f1f1, #1b1b1b));
19
+ font-family: var(--astryx-font-family-body, inherit);
20
+ cursor: pointer;
21
+ transition-property: border-color, background-color;
22
+ transition-duration: var(--astryx-duration-fast, 125ms);
23
+ transition-timing-function: var(--astryx-ease-standard, cubic-bezier(0.24, 1, 0.4, 1));
24
+ }
25
+
26
+ .astryx-chat-reaction-bar__pill {
27
+ display: inline-flex;
28
+ align-items: center;
29
+ gap: var(--astryx-spacing-1, 4px);
30
+ height: 24px;
31
+ padding-inline: var(--astryx-spacing-2, 8px);
32
+ border-radius: var(--astryx-radius-full, 9999px);
33
+ }
34
+
35
+ .astryx-chat-reaction-bar__pill[data-selected] {
36
+ border-color: var(--astryx-color-accent, currentcolor);
37
+ background-color: var(--astryx-color-accent-muted, light-dark(#f1f1f1, #262626));
38
+ }
39
+
40
+ /* 悬停只加深边框。自己已经选中的胶囊保持强调色,不被悬停盖掉。 */
41
+ @media (hover: hover) {
42
+ .astryx-chat-reaction-bar__pill:hover:where(:not(:disabled, [aria-disabled='true'], [data-selected])),
43
+ .astryx-chat-reaction-bar__add:hover:where(:not(:disabled, [aria-disabled='true'])) {
44
+ border-color: var(--astryx-color-border-emphasized, light-dark(#d4d4d4, #525252));
45
+ }
46
+ }
47
+
48
+ .astryx-chat-reaction-bar__pill:is(:disabled, [aria-disabled='true']),
49
+ .astryx-chat-reaction-bar__add:is(:disabled, [aria-disabled='true']) {
50
+ cursor: default;
51
+ }
52
+
53
+ .astryx-chat-reaction-bar__pill:focus-visible,
54
+ .astryx-chat-reaction-bar__add:focus-visible {
55
+ outline: var(--astryx-focus-outline-width, 2px) var(--astryx-focus-outline-style, solid) var(--astryx-focus-outline-color, currentcolor);
56
+ outline-offset: var(--astryx-focus-outline-offset, 2px);
57
+ }
58
+
59
+ .astryx-chat-reaction-bar__emoji {
60
+ font-size: var(--astryx-text-body-size, 1rem);
61
+ line-height: var(--astryx-text-body-leading, 1.4286);
62
+ }
63
+
64
+ .astryx-chat-reaction-bar__count {
65
+ color: var(--astryx-color-text-secondary, light-dark(#6a6a6a, #9e9e9e));
66
+ font-size: var(--astryx-text-supporting-size, 0.75rem);
67
+ font-weight: var(--astryx-font-weight-medium, 500);
68
+ font-variant-numeric: tabular-nums;
69
+ line-height: var(--astryx-text-supporting-leading, 1.6667);
70
+ }
71
+
72
+ .astryx-chat-reaction-bar__pill[data-selected] .astryx-chat-reaction-bar__count {
73
+ color: var(--astryx-color-text-accent, currentcolor);
74
+ font-weight: var(--astryx-font-weight-semibold, 600);
75
+ }
76
+
77
+ .astryx-chat-reaction-bar__add {
78
+ display: inline-flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ width: 32px;
82
+ height: 24px;
83
+ padding: 0;
84
+ border-radius: var(--astryx-radius-full, 9999px);
85
+ color: var(--astryx-color-icon-secondary, light-dark(#6a6a6a, #9e9e9e));
86
+ font-size: 15px;
87
+ line-height: var(--astryx-text-supporting-leading, 1.6667);
88
+ }
89
+
90
+ @media (prefers-reduced-motion: reduce) {
91
+ .astryx-chat-reaction-bar__pill,
92
+ .astryx-chat-reaction-bar__add {
93
+ transition-duration: 0s;
94
+ }
95
+ }
96
+ }