@polymorfa/ui 0.1.0-dev.20260922094209
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/LICENSE +21 -0
- package/README.md +181 -0
- package/dist/appearance.d.ts +69 -0
- package/dist/appearance.d.ts.map +1 -0
- package/dist/appearance.js +123 -0
- package/dist/appearance.js.map +1 -0
- package/dist/chat.d.ts +83 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +144 -0
- package/dist/chat.js.map +1 -0
- package/dist/composer.d.ts +76 -0
- package/dist/composer.d.ts.map +1 -0
- package/dist/composer.js +99 -0
- package/dist/composer.js.map +1 -0
- package/dist/emoji-data.d.ts +9 -0
- package/dist/emoji-data.d.ts.map +1 -0
- package/dist/emoji-data.js +451 -0
- package/dist/emoji-data.js.map +1 -0
- package/dist/emoji.d.ts +36 -0
- package/dist/emoji.d.ts.map +1 -0
- package/dist/emoji.js +134 -0
- package/dist/emoji.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/locale.d.ts +183 -0
- package/dist/locale.d.ts.map +1 -0
- package/dist/locale.js +184 -0
- package/dist/locale.js.map +1 -0
- package/dist/redaction.d.ts +2 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +30 -0
- package/dist/redaction.js.map +1 -0
- package/dist/slots.d.ts +24 -0
- package/dist/slots.d.ts.map +1 -0
- package/dist/slots.js +96 -0
- package/dist/slots.js.map +1 -0
- package/dist/styles.d.ts +19 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +1223 -0
- package/dist/styles.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Polymorfa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# `@polymorfa/ui`
|
|
2
|
+
|
|
3
|
+
Shared appearance, localization, and safe diagnostic contracts for Polymorfa browser components.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { createLocale, defineAppearance } from "@polymorfa/ui";
|
|
7
|
+
|
|
8
|
+
const appearance = defineAppearance({
|
|
9
|
+
variables: { colorPrimary: "#7c3aed" },
|
|
10
|
+
layout: { density: "compact" },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const locale = createLocale("ar-LB", { "common.cancel": "إلغاء" });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The appearance object is immutable and shared by the Web Component, React, and development-tool packages. CSS variable names use the stable `--pmfa-*` prefix. Partial locale dictionaries fall back to the bundled English messages.
|
|
17
|
+
|
|
18
|
+
`redactDiagnostic()` recursively removes credentials, authorization values, secrets, and message bodies before diagnostic data is displayed or copied.
|
|
19
|
+
|
|
20
|
+
## Styling
|
|
21
|
+
|
|
22
|
+
The chat and template components in `@polymorfa/react` and
|
|
23
|
+
`@polymorfa/elements` share one stylesheet, `COMPONENT_STYLES`. You can
|
|
24
|
+
restyle them at five levels, from lightest to fullest control.
|
|
25
|
+
|
|
26
|
+
### Variables
|
|
27
|
+
|
|
28
|
+
`appearance.variables` become CSS custom properties on each component root:
|
|
29
|
+
|
|
30
|
+
| Variable | CSS property |
|
|
31
|
+
| ----------------------------------------------- | ----------------------------------------------------------------------- |
|
|
32
|
+
| `colorPrimary` | `--pmfa-color-primary` |
|
|
33
|
+
| `colorBackground` | `--pmfa-color-background` |
|
|
34
|
+
| `colorForeground` | `--pmfa-color-foreground` |
|
|
35
|
+
| `colorMuted` | `--pmfa-color-muted` |
|
|
36
|
+
| `colorBorder` | `--pmfa-color-border` |
|
|
37
|
+
| `colorDanger` | `--pmfa-color-danger` |
|
|
38
|
+
| `colorSuccess` | `--pmfa-color-success` |
|
|
39
|
+
| `fontFamily` | `--pmfa-font-family` |
|
|
40
|
+
| `fontSizeBase` | `--pmfa-font-size-base` |
|
|
41
|
+
| `spacingSmall`, `spacingMedium`, `spacingLarge` | `--pmfa-spacing-small`, `--pmfa-spacing-medium`, `--pmfa-spacing-large` |
|
|
42
|
+
| `radiusSmall`, `radiusMedium`, `radiusLarge` | `--pmfa-radius-small`, `--pmfa-radius-medium`, `--pmfa-radius-large` |
|
|
43
|
+
| `shadowPanel` | `--pmfa-shadow-panel` |
|
|
44
|
+
| `motion` | `--pmfa-motion` |
|
|
45
|
+
|
|
46
|
+
`layout.drawerWidth` sets `--pmfa-drawer-width`.
|
|
47
|
+
|
|
48
|
+
### Dark colors
|
|
49
|
+
|
|
50
|
+
`theme: "dark"` uses the dark palette; `theme: "system"` uses it when the
|
|
51
|
+
system prefers dark. `darkVariables` overrides its colors one by one and is
|
|
52
|
+
emitted as `--pmfa-dark-color-*` (for example `--pmfa-dark-color-primary`).
|
|
53
|
+
Only color keys apply. Unset dark colors use the built-in dark palette, except
|
|
54
|
+
`colorPrimary`, which falls back to your light primary.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
defineAppearance({
|
|
58
|
+
theme: "system",
|
|
59
|
+
variables: { colorPrimary: "#0f766e" },
|
|
60
|
+
darkVariables: { colorPrimary: "#14b8a6", colorBackground: "#0b1716" },
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Cascade layer
|
|
65
|
+
|
|
66
|
+
Every bundled rule sits in `@layer polymorfa`. Any unlayered CSS in your app
|
|
67
|
+
overrides it, whatever its specificity:
|
|
68
|
+
|
|
69
|
+
```css
|
|
70
|
+
.pmfa-bubble {
|
|
71
|
+
border-radius: 6px;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Unstyled mode
|
|
76
|
+
|
|
77
|
+
`unstyled: true` skips the bundled stylesheet: React does not add it to the
|
|
78
|
+
document, and Web Components do not adopt it. Components still render their
|
|
79
|
+
`pmfa-*` classes, `data-slot` attributes (React), and `part` names (Web
|
|
80
|
+
Components), so you can style them from scratch.
|
|
81
|
+
|
|
82
|
+
React adds the bundled stylesheet to the document once, the first time a
|
|
83
|
+
styled component mounts, and it stays there. Its `pmfa-*` rules then also
|
|
84
|
+
match unstyled React components on the same page. Keep `unstyled: true` for
|
|
85
|
+
every React component on a page (or style the unstyled ones with unlayered
|
|
86
|
+
CSS, which overrides the bundled `@layer polymorfa` rules). Web Components
|
|
87
|
+
keep styles inside each shadow root, so they are not affected.
|
|
88
|
+
|
|
89
|
+
### Slots
|
|
90
|
+
|
|
91
|
+
Every structural node has a slot name. `appearance.elements[slot]` accepts a
|
|
92
|
+
`className` and inline `styles` (camelCase, kebab-case, or `--custom`
|
|
93
|
+
properties) for that node. React components also take a `classNames` prop
|
|
94
|
+
keyed by slot and set `data-slot` on each node. Web Components add the
|
|
95
|
+
kebab-case slot name to the node's `part` attribute.
|
|
96
|
+
|
|
97
|
+
| Slot | `part` | Node |
|
|
98
|
+
| ----------------- | ------------------ | ------------------------------------ |
|
|
99
|
+
| `messageList` | `message-list` | Scrolling message log (`role="log"`) |
|
|
100
|
+
| `message` | `message` | One message row |
|
|
101
|
+
| `bubble` | `bubble` | Message bubble |
|
|
102
|
+
| `messageMeta` | `message-meta` | Time and delivery status |
|
|
103
|
+
| `messageActions` | `message-actions` | Reply and Retry group |
|
|
104
|
+
| `replyButton` | `reply-button` | Reply action |
|
|
105
|
+
| `retryButton` | `retry-button` | Retry action on a failed message |
|
|
106
|
+
| `attachment` | `attachment` | Image thumbnail or file card |
|
|
107
|
+
| `replyQuote` | `reply-quote` | Quoted message above a reply |
|
|
108
|
+
| `dateSeparator` | `date-separator` | "Today", "Yesterday", or a date |
|
|
109
|
+
| `loadMore` | `load-more` | Load earlier messages button |
|
|
110
|
+
| `empty` | `empty` | Empty-conversation text |
|
|
111
|
+
| `composer` | `composer` | Composer form |
|
|
112
|
+
| `composerInput` | `composer-input` | Message textarea |
|
|
113
|
+
| `composerSend` | `composer-send` | Send button |
|
|
114
|
+
| `composerAttach` | `composer-attach` | Attach button |
|
|
115
|
+
| `composerToolbar` | `composer-toolbar` | Composer button and field row |
|
|
116
|
+
| `emojiButton` | `emoji-button` | Emoji picker button |
|
|
117
|
+
| `emojiPicker` | `emoji-picker` | Emoji picker popover |
|
|
118
|
+
| `voiceButton` | `voice-button` | Record voice note button |
|
|
119
|
+
| `recordingBar` | `recording-bar` | Voice note recording bar |
|
|
120
|
+
| `quickReplyMenu` | `quick-reply-menu` | "/" quick reply list |
|
|
121
|
+
| `attachmentChip` | `attachment-chip` | Pending attachment |
|
|
122
|
+
| `replyBanner` | `reply-banner` | "Replying to …" banner |
|
|
123
|
+
| `drawer` | `drawer` | Drawer panel |
|
|
124
|
+
| `drawerHeader` | `drawer-header` | Drawer header |
|
|
125
|
+
| `drawerTitle` | `drawer-title` | Drawer title |
|
|
126
|
+
| `drawerClose` | `drawer-close` | Drawer close button |
|
|
127
|
+
| `templateBuilder` | `template-builder` | Template builder panel |
|
|
128
|
+
| `field` | `field` | Labelled field or field group |
|
|
129
|
+
| `label` | `label` | Field label |
|
|
130
|
+
| `input` | `input` | Template input or textarea |
|
|
131
|
+
| `actions` | `actions` | Template action row |
|
|
132
|
+
| `primaryButton` | `primary-button` | Save draft |
|
|
133
|
+
| `button` | `button` | Preview and Submit to Meta |
|
|
134
|
+
| `preview` | `preview-panel` | Template preview area |
|
|
135
|
+
| `error` | `error` | Error message |
|
|
136
|
+
|
|
137
|
+
`COMPONENT_SLOTS` lists them, and `slotPartName()` converts a slot to its
|
|
138
|
+
part name (`preview` maps to `preview-panel`, because the
|
|
139
|
+
Preview button already uses `preview`). Web Components keep their earlier part names as well, such as
|
|
140
|
+
`meta`, `input`, `send`, `header`, `title`, and `close`.
|
|
141
|
+
|
|
142
|
+
### Composer helpers
|
|
143
|
+
|
|
144
|
+
The React and Web Component composers share these exports, which you can
|
|
145
|
+
use in a custom composer:
|
|
146
|
+
|
|
147
|
+
- `QuickReplyOption`, `findQuickReplyQuery()`, `filterQuickReplies()`, and
|
|
148
|
+
`applyQuickReply()` for "/" quick replies.
|
|
149
|
+
- `insertText()` inserts at a caret or over a selection.
|
|
150
|
+
- `emojiList()`, `emojiInCategory()`, `searchEmoji()`, `readRecentEmoji()`,
|
|
151
|
+
and `recordRecentEmoji()` expose the built-in set of about 430 emoji with
|
|
152
|
+
English names and keywords. It lives in its own module, so bundlers drop
|
|
153
|
+
it when nothing imports it.
|
|
154
|
+
- `placePopover()` positions a fixed popover beside an anchor inside the
|
|
155
|
+
viewport, and `formatElapsed()` formats a recording time as `mm:ss`.
|
|
156
|
+
|
|
157
|
+
### Web Component stylesheets
|
|
158
|
+
|
|
159
|
+
Style Web Components from the page with `::part()`:
|
|
160
|
+
|
|
161
|
+
```css
|
|
162
|
+
pmfa-message-list::part(bubble) {
|
|
163
|
+
border-radius: 6px;
|
|
164
|
+
}
|
|
165
|
+
pmfa-chat-drawer::part(drawer-header) {
|
|
166
|
+
background: #0f766e;
|
|
167
|
+
color: white;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
For rules that `::part()` cannot express, such as descendants or states,
|
|
172
|
+
pass `configuration.stylesheet`. It takes CSS text, a `CSSStyleSheet`, or an
|
|
173
|
+
array of either, and is adopted inside the shadow root after the default
|
|
174
|
+
stylesheet:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
element.configuration = {
|
|
178
|
+
appearance: { theme: "dark" },
|
|
179
|
+
stylesheet: `.pmfa-msg-out .pmfa-bubble { border-end-end-radius: 18px; }`,
|
|
180
|
+
};
|
|
181
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type Theme = "light" | "dark" | "system";
|
|
2
|
+
export type MotionPreference = "full" | "reduced" | "system";
|
|
3
|
+
export type Density = "comfortable" | "compact";
|
|
4
|
+
export type Direction = "ltr" | "rtl" | "auto";
|
|
5
|
+
export interface AppearanceVariables {
|
|
6
|
+
readonly colorPrimary: string;
|
|
7
|
+
readonly colorBackground: string;
|
|
8
|
+
readonly colorForeground: string;
|
|
9
|
+
readonly colorMuted: string;
|
|
10
|
+
readonly colorBorder: string;
|
|
11
|
+
readonly colorDanger: string;
|
|
12
|
+
readonly colorSuccess: string;
|
|
13
|
+
readonly fontFamily: string;
|
|
14
|
+
readonly fontSizeBase: string;
|
|
15
|
+
readonly spacingSmall: string;
|
|
16
|
+
readonly spacingMedium: string;
|
|
17
|
+
readonly spacingLarge: string;
|
|
18
|
+
readonly radiusSmall: string;
|
|
19
|
+
readonly radiusMedium: string;
|
|
20
|
+
readonly radiusLarge: string;
|
|
21
|
+
readonly shadowPanel: string;
|
|
22
|
+
readonly motion: MotionPreference;
|
|
23
|
+
}
|
|
24
|
+
export interface AppearanceLayout {
|
|
25
|
+
readonly density: Density;
|
|
26
|
+
readonly direction: Direction;
|
|
27
|
+
readonly drawerWidth: string;
|
|
28
|
+
readonly dialogWidth: string;
|
|
29
|
+
readonly callAspectRatio: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ElementAppearance {
|
|
32
|
+
readonly className?: string;
|
|
33
|
+
readonly surface?: "flat" | "raised" | "overlay";
|
|
34
|
+
readonly styles?: Readonly<Record<string, string>>;
|
|
35
|
+
}
|
|
36
|
+
/** The color variables, which the dark palette can override one by one. */
|
|
37
|
+
export type AppearanceColorVariable = Extract<keyof AppearanceVariables, `color${string}`>;
|
|
38
|
+
export interface Appearance {
|
|
39
|
+
readonly theme: Theme;
|
|
40
|
+
readonly variables: AppearanceVariables;
|
|
41
|
+
/**
|
|
42
|
+
* Colors for the dark theme (`theme: "dark"`, or `"system"` when the system
|
|
43
|
+
* prefers dark). Only color keys apply; unset keys use the built-in dark
|
|
44
|
+
* palette.
|
|
45
|
+
*/
|
|
46
|
+
readonly darkVariables?: Partial<AppearanceVariables>;
|
|
47
|
+
/** Skip the bundled stylesheet; components still render their classes and parts. */
|
|
48
|
+
readonly unstyled?: boolean;
|
|
49
|
+
readonly layout: AppearanceLayout;
|
|
50
|
+
readonly elements: Readonly<Record<string, ElementAppearance>>;
|
|
51
|
+
}
|
|
52
|
+
export interface AppearanceInput {
|
|
53
|
+
readonly theme?: Theme;
|
|
54
|
+
readonly variables?: Partial<AppearanceVariables>;
|
|
55
|
+
readonly darkVariables?: Partial<AppearanceVariables>;
|
|
56
|
+
readonly unstyled?: boolean;
|
|
57
|
+
readonly layout?: Partial<AppearanceLayout>;
|
|
58
|
+
readonly elements?: Readonly<Record<string, ElementAppearance>>;
|
|
59
|
+
}
|
|
60
|
+
export declare const DEFAULT_APPEARANCE: Appearance;
|
|
61
|
+
export declare function defineAppearance(input?: AppearanceInput): Appearance;
|
|
62
|
+
export declare function mergeAppearance(base: AppearanceInput, override: AppearanceInput): Appearance;
|
|
63
|
+
/**
|
|
64
|
+
* CSS custom properties for an appearance. Dark colors that are set also
|
|
65
|
+
* emit `--pmfa-dark-color-*`, which the stylesheet reads in the dark theme.
|
|
66
|
+
*/
|
|
67
|
+
export declare function appearanceToCssVariables(appearance: Appearance): Readonly<Record<string, string>>;
|
|
68
|
+
export declare function resolveMotionPreference(preference: MotionPreference, systemPrefersReduced: boolean): Exclude<MotionPreference, "system">;
|
|
69
|
+
//# sourceMappingURL=appearance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appearance.d.ts","sourceRoot":"","sources":["../src/appearance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const DEFAULT_APPEARANCE_VALUE = {
|
|
2
|
+
theme: "system",
|
|
3
|
+
variables: {
|
|
4
|
+
colorPrimary: "#5b4bf7",
|
|
5
|
+
colorBackground: "#ffffff",
|
|
6
|
+
colorForeground: "#17151f",
|
|
7
|
+
colorMuted: "#6d6878",
|
|
8
|
+
colorBorder: "#dedbe5",
|
|
9
|
+
colorDanger: "#c62828",
|
|
10
|
+
colorSuccess: "#18794e",
|
|
11
|
+
fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
12
|
+
fontSizeBase: "16px",
|
|
13
|
+
spacingSmall: "8px",
|
|
14
|
+
spacingMedium: "12px",
|
|
15
|
+
spacingLarge: "20px",
|
|
16
|
+
radiusSmall: "6px",
|
|
17
|
+
radiusMedium: "10px",
|
|
18
|
+
radiusLarge: "16px",
|
|
19
|
+
shadowPanel: "0 18px 50px rgb(23 21 31 / 0.16)",
|
|
20
|
+
motion: "system",
|
|
21
|
+
},
|
|
22
|
+
layout: {
|
|
23
|
+
density: "comfortable",
|
|
24
|
+
direction: "auto",
|
|
25
|
+
drawerWidth: "400px",
|
|
26
|
+
dialogWidth: "440px",
|
|
27
|
+
callAspectRatio: "16 / 9",
|
|
28
|
+
},
|
|
29
|
+
elements: {},
|
|
30
|
+
};
|
|
31
|
+
export const DEFAULT_APPEARANCE = deepFreeze(DEFAULT_APPEARANCE_VALUE);
|
|
32
|
+
export function defineAppearance(input = {}) {
|
|
33
|
+
return mergeAppearance(DEFAULT_APPEARANCE, input);
|
|
34
|
+
}
|
|
35
|
+
export function mergeAppearance(base, override) {
|
|
36
|
+
const baseVariables = { ...DEFAULT_APPEARANCE.variables, ...base.variables };
|
|
37
|
+
const baseLayout = { ...DEFAULT_APPEARANCE.layout, ...base.layout };
|
|
38
|
+
const elements = {};
|
|
39
|
+
for (const name of new Set([
|
|
40
|
+
...Object.keys(base.elements ?? {}),
|
|
41
|
+
...Object.keys(override.elements ?? {}),
|
|
42
|
+
])) {
|
|
43
|
+
const baseElement = base.elements?.[name];
|
|
44
|
+
const overrideElement = override.elements?.[name];
|
|
45
|
+
elements[name] = {
|
|
46
|
+
...baseElement,
|
|
47
|
+
...overrideElement,
|
|
48
|
+
...(baseElement?.styles === undefined &&
|
|
49
|
+
overrideElement?.styles === undefined
|
|
50
|
+
? {}
|
|
51
|
+
: { styles: { ...baseElement?.styles, ...overrideElement?.styles } }),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const darkVariables = base.darkVariables === undefined && override.darkVariables === undefined
|
|
55
|
+
? undefined
|
|
56
|
+
: { ...base.darkVariables, ...override.darkVariables };
|
|
57
|
+
const unstyled = override.unstyled ?? base.unstyled;
|
|
58
|
+
return deepFreeze({
|
|
59
|
+
theme: override.theme ?? base.theme ?? DEFAULT_APPEARANCE.theme,
|
|
60
|
+
variables: { ...baseVariables, ...override.variables },
|
|
61
|
+
...(darkVariables === undefined ? {} : { darkVariables }),
|
|
62
|
+
...(unstyled === undefined ? {} : { unstyled }),
|
|
63
|
+
layout: { ...baseLayout, ...override.layout },
|
|
64
|
+
elements,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const CSS_VARIABLES = {
|
|
68
|
+
colorPrimary: "--pmfa-color-primary",
|
|
69
|
+
colorBackground: "--pmfa-color-background",
|
|
70
|
+
colorForeground: "--pmfa-color-foreground",
|
|
71
|
+
colorMuted: "--pmfa-color-muted",
|
|
72
|
+
colorBorder: "--pmfa-color-border",
|
|
73
|
+
colorDanger: "--pmfa-color-danger",
|
|
74
|
+
colorSuccess: "--pmfa-color-success",
|
|
75
|
+
fontFamily: "--pmfa-font-family",
|
|
76
|
+
fontSizeBase: "--pmfa-font-size-base",
|
|
77
|
+
spacingSmall: "--pmfa-spacing-small",
|
|
78
|
+
spacingMedium: "--pmfa-spacing-medium",
|
|
79
|
+
spacingLarge: "--pmfa-spacing-large",
|
|
80
|
+
radiusSmall: "--pmfa-radius-small",
|
|
81
|
+
radiusMedium: "--pmfa-radius-medium",
|
|
82
|
+
radiusLarge: "--pmfa-radius-large",
|
|
83
|
+
shadowPanel: "--pmfa-shadow-panel",
|
|
84
|
+
motion: "--pmfa-motion",
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* CSS custom properties for an appearance. Dark colors that are set also
|
|
88
|
+
* emit `--pmfa-dark-color-*`, which the stylesheet reads in the dark theme.
|
|
89
|
+
*/
|
|
90
|
+
export function appearanceToCssVariables(appearance) {
|
|
91
|
+
const light = Object.entries(CSS_VARIABLES).map(([key, cssName]) => [
|
|
92
|
+
cssName,
|
|
93
|
+
appearance.variables[key],
|
|
94
|
+
]);
|
|
95
|
+
const dark = Object.entries(CSS_VARIABLES).flatMap(([key, cssName]) => {
|
|
96
|
+
const value = appearance.darkVariables?.[key];
|
|
97
|
+
return key.startsWith("color") && value !== undefined
|
|
98
|
+
? [
|
|
99
|
+
[
|
|
100
|
+
cssName.replace("--pmfa-color-", "--pmfa-dark-color-"),
|
|
101
|
+
value,
|
|
102
|
+
],
|
|
103
|
+
]
|
|
104
|
+
: [];
|
|
105
|
+
});
|
|
106
|
+
const entries = [...light, ...dark].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
107
|
+
return Object.freeze(Object.fromEntries(entries));
|
|
108
|
+
}
|
|
109
|
+
export function resolveMotionPreference(preference, systemPrefersReduced) {
|
|
110
|
+
return preference === "system"
|
|
111
|
+
? systemPrefersReduced
|
|
112
|
+
? "reduced"
|
|
113
|
+
: "full"
|
|
114
|
+
: preference;
|
|
115
|
+
}
|
|
116
|
+
function deepFreeze(value) {
|
|
117
|
+
if (typeof value !== "object" || value === null || Object.isFrozen(value))
|
|
118
|
+
return value;
|
|
119
|
+
for (const child of Object.values(value))
|
|
120
|
+
deepFreeze(child);
|
|
121
|
+
return Object.freeze(value);
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=appearance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appearance.js","sourceRoot":"","sources":["../src/appearance.ts"],"names":[],"mappings":"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"}
|
package/dist/chat.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering helpers shared by the React and Web Component chat surfaces, so
|
|
3
|
+
* both group, date, and format messages the same way.
|
|
4
|
+
*/
|
|
5
|
+
export interface ChatLayoutMessage {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly createdAt: number;
|
|
8
|
+
readonly direction: "inbound" | "outbound";
|
|
9
|
+
}
|
|
10
|
+
export type ChatLayoutEntry<T extends ChatLayoutMessage> = {
|
|
11
|
+
readonly kind: "date";
|
|
12
|
+
/** Stable across renders: `date:YYYY-M-D` in local time. */
|
|
13
|
+
readonly key: string;
|
|
14
|
+
readonly time: number;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: "message";
|
|
17
|
+
readonly key: string;
|
|
18
|
+
readonly message: T;
|
|
19
|
+
/** First message of a run from the same side on the same day. */
|
|
20
|
+
readonly groupStart: boolean;
|
|
21
|
+
/** Last message of that run. */
|
|
22
|
+
readonly groupEnd: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Oldest first; messages without a valid time sort as the newest. */
|
|
25
|
+
export declare function compareMessageTime(left: {
|
|
26
|
+
readonly createdAt: number;
|
|
27
|
+
}, right: {
|
|
28
|
+
readonly createdAt: number;
|
|
29
|
+
}): number;
|
|
30
|
+
/** Local calendar day of a timestamp, or `undefined` for an invalid time. */
|
|
31
|
+
export declare function messageDayKey(time: number): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Sort messages oldest first, insert a date separator before each new day,
|
|
34
|
+
* and mark runs of consecutive messages from the same side.
|
|
35
|
+
*/
|
|
36
|
+
export declare function layoutMessages<T extends ChatLayoutMessage>(messages: readonly T[]): readonly ChatLayoutEntry<T>[];
|
|
37
|
+
/** "Today", "Yesterday", or the localized date. */
|
|
38
|
+
export declare function formatDayLabel(time: number, localeCode: string, labels: {
|
|
39
|
+
readonly today: string;
|
|
40
|
+
readonly yesterday: string;
|
|
41
|
+
}, now?: number): string;
|
|
42
|
+
/** Localized time of day, or `undefined` for an invalid time. */
|
|
43
|
+
export declare function formatMessageTime(time: number, localeCode: string): string | undefined;
|
|
44
|
+
/** Human-readable file size, such as `1.4 MB`, in the given locale. */
|
|
45
|
+
export declare function formatFileSize(bytes: number, localeCode: string): string;
|
|
46
|
+
export declare function isImageAttachment(attachment: {
|
|
47
|
+
readonly contentType: string;
|
|
48
|
+
}): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* `url` when it is an absolute `https:`, `http:`, or `blob:` URL, otherwise
|
|
51
|
+
* `undefined`. Use it before placing an attachment URL in `href` or `src`, so
|
|
52
|
+
* `javascript:` and other schemes never reach the DOM.
|
|
53
|
+
*/
|
|
54
|
+
export declare function safeAttachmentUrl(url: string | undefined | null): string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Outline icons (24×24, 2px stroke) used by the chat surfaces. Each value is
|
|
57
|
+
* the `d` attribute of a single `<path>`.
|
|
58
|
+
*/
|
|
59
|
+
export declare const CHAT_ICONS: {
|
|
60
|
+
readonly close: "M18 6 6 18M6 6l12 12";
|
|
61
|
+
readonly send: "M12 19V5M5 12l7-7 7 7";
|
|
62
|
+
readonly attach: "m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48";
|
|
63
|
+
readonly reply: "M9 17 4 12l5-5M20 18v-2a4 4 0 0 0-4-4H4";
|
|
64
|
+
readonly retry: "M3 12a9 9 0 1 0 2.64-6.36L3 8M3 3v5h5";
|
|
65
|
+
readonly pending: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 7v5l3 2";
|
|
66
|
+
readonly sent: "M20 6 9 17l-5-5";
|
|
67
|
+
readonly failed: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 8v4M12 16h.01";
|
|
68
|
+
readonly smiley: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01";
|
|
69
|
+
readonly mic: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3ZM19 10v2a7 7 0 0 1-14 0v-2M12 19v3";
|
|
70
|
+
readonly trash: "M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6M10 11v6M14 11v6";
|
|
71
|
+
readonly search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM21 21l-4.35-4.35";
|
|
72
|
+
readonly sendArrow: "M5 12h14M13 6l6 6-6 6";
|
|
73
|
+
readonly file: "M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9ZM14 3v6h6";
|
|
74
|
+
readonly back: "M15 18l-6-6 6-6";
|
|
75
|
+
readonly info: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 16v-4M12 8h.01";
|
|
76
|
+
readonly phone: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z";
|
|
77
|
+
readonly video: "M23 7l-7 5 7 5V7ZM14 5H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2Z";
|
|
78
|
+
readonly link: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71";
|
|
79
|
+
readonly plus: "M12 5v14M5 12h14";
|
|
80
|
+
readonly inbox: "M22 12h-6l-2 3h-4l-2-3H2M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11Z";
|
|
81
|
+
};
|
|
82
|
+
export type ChatIconName = keyof typeof CHAT_ICONS;
|
|
83
|
+
//# sourceMappingURL=chat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;CAC5C;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,iBAAiB,IACnD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,iEAAiE;IACjE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,gCAAgC;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEN,sEAAsE;AACtE,wBAAgB,kBAAkB,CAChC,IAAI,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EACpC,KAAK,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACpC,MAAM,CAIR;AAMD,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI9D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,iBAAiB,EACxD,QAAQ,EAAE,SAAS,CAAC,EAAE,GACrB,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAyB/B;AAED,mDAAmD;AACnD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC9D,GAAG,GAAE,MAAmB,GACvB,MAAM,CAeR;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,SAAS,CAOpB;AAID,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAaxE;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE;IAC5C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,GAAG,OAAO,CAEV;AAID;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAC7B,MAAM,GAAG,SAAS,CAWpB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;CA4Bb,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,UAAU,CAAC"}
|
package/dist/chat.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering helpers shared by the React and Web Component chat surfaces, so
|
|
3
|
+
* both group, date, and format messages the same way.
|
|
4
|
+
*/
|
|
5
|
+
/** Oldest first; messages without a valid time sort as the newest. */
|
|
6
|
+
export function compareMessageTime(left, right) {
|
|
7
|
+
const a = sortableTime(left.createdAt);
|
|
8
|
+
const b = sortableTime(right.createdAt);
|
|
9
|
+
return a === b ? 0 : a < b ? -1 : 1;
|
|
10
|
+
}
|
|
11
|
+
function sortableTime(value) {
|
|
12
|
+
return Number.isNaN(new Date(value).getTime()) ? Infinity : value;
|
|
13
|
+
}
|
|
14
|
+
/** Local calendar day of a timestamp, or `undefined` for an invalid time. */
|
|
15
|
+
export function messageDayKey(time) {
|
|
16
|
+
const date = new Date(time);
|
|
17
|
+
if (Number.isNaN(date.getTime()))
|
|
18
|
+
return undefined;
|
|
19
|
+
return `date:${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sort messages oldest first, insert a date separator before each new day,
|
|
23
|
+
* and mark runs of consecutive messages from the same side.
|
|
24
|
+
*/
|
|
25
|
+
export function layoutMessages(messages) {
|
|
26
|
+
const sorted = [...messages].sort(compareMessageTime);
|
|
27
|
+
const days = sorted.map((message) => messageDayKey(message.createdAt));
|
|
28
|
+
const entries = [];
|
|
29
|
+
sorted.forEach((message, index) => {
|
|
30
|
+
const day = days[index];
|
|
31
|
+
const previous = sorted[index - 1];
|
|
32
|
+
const next = sorted[index + 1];
|
|
33
|
+
if (day !== undefined && day !== days[index - 1])
|
|
34
|
+
entries.push({ kind: "date", key: day, time: message.createdAt });
|
|
35
|
+
entries.push({
|
|
36
|
+
kind: "message",
|
|
37
|
+
key: message.id,
|
|
38
|
+
message,
|
|
39
|
+
groupStart: previous === undefined ||
|
|
40
|
+
previous.direction !== message.direction ||
|
|
41
|
+
days[index - 1] !== day,
|
|
42
|
+
groupEnd: next === undefined ||
|
|
43
|
+
next.direction !== message.direction ||
|
|
44
|
+
days[index + 1] !== day,
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
return entries;
|
|
48
|
+
}
|
|
49
|
+
/** "Today", "Yesterday", or the localized date. */
|
|
50
|
+
export function formatDayLabel(time, localeCode, labels, now = Date.now()) {
|
|
51
|
+
const day = messageDayKey(time);
|
|
52
|
+
if (day === messageDayKey(now))
|
|
53
|
+
return labels.today;
|
|
54
|
+
const yesterday = new Date(now);
|
|
55
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
56
|
+
if (day === messageDayKey(yesterday.getTime()))
|
|
57
|
+
return labels.yesterday;
|
|
58
|
+
const date = new Date(time);
|
|
59
|
+
return new Intl.DateTimeFormat(localeCode, {
|
|
60
|
+
weekday: "short",
|
|
61
|
+
day: "numeric",
|
|
62
|
+
month: "short",
|
|
63
|
+
...(date.getFullYear() === new Date(now).getFullYear()
|
|
64
|
+
? {}
|
|
65
|
+
: { year: "numeric" }),
|
|
66
|
+
}).format(date);
|
|
67
|
+
}
|
|
68
|
+
/** Localized time of day, or `undefined` for an invalid time. */
|
|
69
|
+
export function formatMessageTime(time, localeCode) {
|
|
70
|
+
const date = new Date(time);
|
|
71
|
+
if (Number.isNaN(date.getTime()))
|
|
72
|
+
return undefined;
|
|
73
|
+
return date.toLocaleTimeString(localeCode, {
|
|
74
|
+
hour: "numeric",
|
|
75
|
+
minute: "2-digit",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const SIZE_UNITS = ["byte", "kilobyte", "megabyte", "gigabyte"];
|
|
79
|
+
/** Human-readable file size, such as `1.4 MB`, in the given locale. */
|
|
80
|
+
export function formatFileSize(bytes, localeCode) {
|
|
81
|
+
let value = Math.max(0, bytes);
|
|
82
|
+
let unit = 0;
|
|
83
|
+
while (value >= 1024 && unit < SIZE_UNITS.length - 1) {
|
|
84
|
+
value /= 1024;
|
|
85
|
+
unit += 1;
|
|
86
|
+
}
|
|
87
|
+
return new Intl.NumberFormat(localeCode, {
|
|
88
|
+
style: "unit",
|
|
89
|
+
unit: SIZE_UNITS[unit],
|
|
90
|
+
unitDisplay: unit === 0 ? "long" : "short",
|
|
91
|
+
maximumFractionDigits: unit === 0 || value >= 10 ? 0 : 1,
|
|
92
|
+
}).format(value);
|
|
93
|
+
}
|
|
94
|
+
export function isImageAttachment(attachment) {
|
|
95
|
+
return attachment.contentType.toLowerCase().startsWith("image/");
|
|
96
|
+
}
|
|
97
|
+
const SAFE_ATTACHMENT_PROTOCOLS = new Set(["https:", "http:", "blob:"]);
|
|
98
|
+
/**
|
|
99
|
+
* `url` when it is an absolute `https:`, `http:`, or `blob:` URL, otherwise
|
|
100
|
+
* `undefined`. Use it before placing an attachment URL in `href` or `src`, so
|
|
101
|
+
* `javascript:` and other schemes never reach the DOM.
|
|
102
|
+
*/
|
|
103
|
+
export function safeAttachmentUrl(url) {
|
|
104
|
+
if (typeof url !== "string" || url.trim() === "")
|
|
105
|
+
return undefined;
|
|
106
|
+
let parsed;
|
|
107
|
+
try {
|
|
108
|
+
parsed = new URL(url.trim());
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
return SAFE_ATTACHMENT_PROTOCOLS.has(parsed.protocol)
|
|
114
|
+
? parsed.href
|
|
115
|
+
: undefined;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Outline icons (24×24, 2px stroke) used by the chat surfaces. Each value is
|
|
119
|
+
* the `d` attribute of a single `<path>`.
|
|
120
|
+
*/
|
|
121
|
+
export const CHAT_ICONS = {
|
|
122
|
+
close: "M18 6 6 18M6 6l12 12",
|
|
123
|
+
send: "M12 19V5M5 12l7-7 7 7",
|
|
124
|
+
attach: "m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48",
|
|
125
|
+
reply: "M9 17 4 12l5-5M20 18v-2a4 4 0 0 0-4-4H4",
|
|
126
|
+
retry: "M3 12a9 9 0 1 0 2.64-6.36L3 8M3 3v5h5",
|
|
127
|
+
pending: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 7v5l3 2",
|
|
128
|
+
sent: "M20 6 9 17l-5-5",
|
|
129
|
+
failed: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 8v4M12 16h.01",
|
|
130
|
+
smiley: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01",
|
|
131
|
+
mic: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3ZM19 10v2a7 7 0 0 1-14 0v-2M12 19v3",
|
|
132
|
+
trash: "M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6M10 11v6M14 11v6",
|
|
133
|
+
search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM21 21l-4.35-4.35",
|
|
134
|
+
sendArrow: "M5 12h14M13 6l6 6-6 6",
|
|
135
|
+
file: "M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9ZM14 3v6h6",
|
|
136
|
+
back: "M15 18l-6-6 6-6",
|
|
137
|
+
info: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 16v-4M12 8h.01",
|
|
138
|
+
phone: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z",
|
|
139
|
+
video: "M23 7l-7 5 7 5V7ZM14 5H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2Z",
|
|
140
|
+
link: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",
|
|
141
|
+
plus: "M12 5v14M5 12h14",
|
|
142
|
+
inbox: "M22 12h-6l-2 3h-4l-2-3H2M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11Z",
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=chat.js.map
|
package/dist/chat.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"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"}
|