@smwb/ui-react 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_LESS_OVERRIDES.md +84 -21
- package/AI_THEMING.md +72 -28
- package/README.md +654 -0
- package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
- package/dist/assets/styles/less/components/button/button.entry.css +1 -1
- package/dist/assets/styles/less/components/checkbox/checkbox.entry.css +1 -1
- package/dist/assets/styles/less/components/chip/chip.entry.css +1 -1
- package/dist/assets/styles/less/components/commandPalette/commandPalette.entry.css +1 -0
- package/dist/assets/styles/less/components/composer/composer.entry.css +1 -0
- package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -0
- package/dist/assets/styles/less/components/diffStat/diffStat.entry.css +1 -0
- package/dist/assets/styles/less/components/kbd/kbd.entry.css +1 -0
- package/dist/assets/styles/less/components/list/list.entry.css +1 -1
- package/dist/assets/styles/less/components/qrCode/qrCode.entry.css +1 -0
- package/dist/assets/styles/less/components/radioButton/radioButton.entry.css +1 -1
- package/dist/assets/styles/less/components/selectField/selectField.entry.css +1 -1
- package/dist/assets/styles/less/components/sidebar/sidebar.entry.css +1 -1
- package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -0
- package/dist/assets/styles/less/components/swimlanes/swimlanes.entry.css +1 -0
- package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -0
- package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
- package/dist/assets/styles/less/components/tabs/tabPanel/tabPanel.entry.css +1 -0
- package/dist/assets/styles/less/components/tabs/tabs.entry.css +1 -1
- package/dist/assets/styles/less/components/textField/textField.entry.css +1 -1
- package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
- package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
- package/dist/assets/styles/less/tokens.entry.css +1 -1
- package/dist/components/dataDisplay/chat/chat.d.ts +43 -1
- package/dist/components/dataDisplay/chat/chat.js +179 -150
- package/dist/components/dataDisplay/chat/chat.js.map +1 -1
- package/dist/components/dataDisplay/chat/chatComposer.d.ts +17 -0
- package/dist/components/dataDisplay/chat/chatComposer.js +31 -29
- package/dist/components/dataDisplay/chat/chatComposer.js.map +1 -1
- package/dist/components/dataDisplay/chat/index.d.ts +1 -1
- package/dist/components/dataDisplay/chat/utils.d.ts +14 -0
- package/dist/components/dataDisplay/chat/utils.js.map +1 -1
- package/dist/components/dataDisplay/dagView/dagLayout.d.ts +74 -0
- package/dist/components/dataDisplay/dagView/dagLayout.js +289 -0
- package/dist/components/dataDisplay/dagView/dagLayout.js.map +1 -0
- package/dist/components/dataDisplay/dagView/dagView.d.ts +157 -0
- package/dist/components/dataDisplay/dagView/dagView.js +543 -0
- package/dist/components/dataDisplay/dagView/dagView.js.map +1 -0
- package/dist/components/dataDisplay/dagView/index.d.ts +4 -0
- package/dist/components/dataDisplay/dagView/panZoom.d.ts +75 -0
- package/dist/components/dataDisplay/dagView/panZoom.js +171 -0
- package/dist/components/dataDisplay/dagView/panZoom.js.map +1 -0
- package/dist/components/dataDisplay/diffStat/diffStat.d.ts +54 -0
- package/dist/components/dataDisplay/diffStat/diffStat.js +63 -0
- package/dist/components/dataDisplay/diffStat/diffStat.js.map +1 -0
- package/dist/components/dataDisplay/diffStat/index.d.ts +2 -0
- package/dist/components/dataDisplay/kbd/index.d.ts +4 -0
- package/dist/components/dataDisplay/kbd/kbd.d.ts +40 -0
- package/dist/components/dataDisplay/kbd/kbd.js +27 -0
- package/dist/components/dataDisplay/kbd/kbd.js.map +1 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.d.ts +18 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.js +72 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
- package/dist/components/dataDisplay/list/listItem.d.ts +34 -0
- package/dist/components/dataDisplay/list/listItem.js +47 -24
- package/dist/components/dataDisplay/list/listItem.js.map +1 -1
- package/dist/components/dataDisplay/qrCode/index.d.ts +2 -0
- package/dist/components/dataDisplay/qrCode/qrCode.d.ts +28 -0
- package/dist/components/dataDisplay/qrCode/qrCode.js +78 -0
- package/dist/components/dataDisplay/qrCode/qrCode.js.map +1 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.d.ts +7 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.js +20 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
- package/dist/components/dataDisplay/statusDot/index.d.ts +2 -0
- package/dist/components/dataDisplay/statusDot/statusDot.d.ts +35 -0
- package/dist/components/dataDisplay/statusDot/statusDot.js +30 -0
- package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -0
- package/dist/components/dataDisplay/swimlanes/index.d.ts +2 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.d.ts +53 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.js +357 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
- package/dist/components/dataDisplay/treeView/treeView.d.ts +17 -1
- package/dist/components/dataDisplay/treeView/treeView.js +113 -92
- package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/components/feedBack/modal/modal.js +84 -63
- package/dist/components/feedBack/modal/modal.js.map +1 -1
- package/dist/components/inputs/button/button.d.ts +13 -1
- package/dist/components/inputs/button/button.js +57 -51
- package/dist/components/inputs/button/button.js.map +1 -1
- package/dist/components/inputs/composer/composer.d.ts +149 -0
- package/dist/components/inputs/composer/composer.js +219 -0
- package/dist/components/inputs/composer/composer.js.map +1 -0
- package/dist/components/inputs/composer/composerFiles.d.ts +26 -0
- package/dist/components/inputs/composer/composerFiles.js +19 -0
- package/dist/components/inputs/composer/composerFiles.js.map +1 -0
- package/dist/components/inputs/composer/composerKeys.d.ts +29 -0
- package/dist/components/inputs/composer/composerKeys.js +7 -0
- package/dist/components/inputs/composer/composerKeys.js.map +1 -0
- package/dist/components/inputs/composer/index.d.ts +3 -0
- package/dist/components/layout/sheet/sheet.d.ts +12 -0
- package/dist/components/layout/sheet/sheet.js +152 -137
- package/dist/components/layout/sheet/sheet.js.map +1 -1
- package/dist/components/layout/tabGroups/index.d.ts +4 -0
- package/dist/components/layout/tabGroups/tabGroups.d.ts +94 -0
- package/dist/components/layout/tabGroups/tabGroups.js +783 -0
- package/dist/components/layout/tabGroups/tabGroups.js.map +1 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +55 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js +199 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.d.ts +250 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.js +497 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
- package/dist/components/navigation/appBar/appBar.d.ts +22 -0
- package/dist/components/navigation/appBar/appBar.js +31 -26
- package/dist/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/components/navigation/commandPalette/commandPalette.d.ts +111 -0
- package/dist/components/navigation/commandPalette/commandPalette.js +337 -0
- package/dist/components/navigation/commandPalette/commandPalette.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.d.ts +11 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.d.ts +13 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteTypes.d.ts +39 -0
- package/dist/components/navigation/commandPalette/index.d.ts +4 -0
- package/dist/components/navigation/sidebar/sidebar.d.ts +10 -0
- package/dist/components/navigation/sidebar/sidebar.js +61 -59
- package/dist/components/navigation/sidebar/sidebar.js.map +1 -1
- package/dist/components/navigation/tabs/index.d.ts +3 -1
- package/dist/components/navigation/tabs/tab/tab.d.ts +88 -1
- package/dist/components/navigation/tabs/tab/tab.js +121 -42
- package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/components/navigation/tabs/tabPanel/tabPanel.d.ts +19 -0
- package/dist/components/navigation/tabs/tabPanel/tabPanel.js +27 -0
- package/dist/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
- package/dist/components/navigation/tabs/tabs.d.ts +75 -5
- package/dist/components/navigation/tabs/tabs.js +369 -145
- package/dist/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/components/navigation/tabs/tabs.utils.d.ts +20 -0
- package/dist/components/navigation/tabs/tabs.utils.js +11 -0
- package/dist/components/navigation/tabs/tabs.utils.js.map +1 -0
- package/dist/components/navigation/tabs/tabsContext.d.ts +11 -0
- package/dist/components/navigation/tabs/tabsContext.js +6 -0
- package/dist/components/navigation/tabs/tabsContext.js.map +1 -0
- package/dist/headless/components/dataDisplay/chat/chat.js +179 -150
- package/dist/headless/components/dataDisplay/chat/chat.js.map +1 -1
- package/dist/headless/components/dataDisplay/chat/chatComposer.js +31 -29
- package/dist/headless/components/dataDisplay/chat/chatComposer.js.map +1 -1
- package/dist/headless/components/dataDisplay/chat/utils.js.map +1 -1
- package/dist/headless/components/dataDisplay/dagView/dagLayout.js +289 -0
- package/dist/headless/components/dataDisplay/dagView/dagLayout.js.map +1 -0
- package/dist/headless/components/dataDisplay/dagView/dagView.js +541 -0
- package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -0
- package/dist/headless/components/dataDisplay/dagView/panZoom.js +171 -0
- package/dist/headless/components/dataDisplay/dagView/panZoom.js.map +1 -0
- package/dist/headless/components/dataDisplay/diffStat/diffStat.js +61 -0
- package/dist/headless/components/dataDisplay/diffStat/diffStat.js.map +1 -0
- package/dist/headless/components/dataDisplay/kbd/kbd.js +25 -0
- package/dist/headless/components/dataDisplay/kbd/kbd.js.map +1 -0
- package/dist/headless/components/dataDisplay/kbd/kbdKeys.js +72 -0
- package/dist/headless/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
- package/dist/headless/components/dataDisplay/list/listItem.js +47 -24
- package/dist/headless/components/dataDisplay/list/listItem.js.map +1 -1
- package/dist/headless/components/dataDisplay/qrCode/qrCode.js +76 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCode.js.map +1 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js +20 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js +28 -0
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -0
- package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js +355 -0
- package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
- package/dist/headless/components/dataDisplay/treeView/treeView.js +113 -92
- package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/headless/components/feedBack/modal/modal.js +85 -64
- package/dist/headless/components/feedBack/modal/modal.js.map +1 -1
- package/dist/headless/components/inputs/button/button.js +56 -50
- package/dist/headless/components/inputs/button/button.js.map +1 -1
- package/dist/headless/components/inputs/composer/composer.js +217 -0
- package/dist/headless/components/inputs/composer/composer.js.map +1 -0
- package/dist/headless/components/inputs/composer/composerFiles.js +19 -0
- package/dist/headless/components/inputs/composer/composerFiles.js.map +1 -0
- package/dist/headless/components/inputs/composer/composerKeys.js +7 -0
- package/dist/headless/components/inputs/composer/composerKeys.js.map +1 -0
- package/dist/headless/components/layout/sheet/sheet.js +160 -145
- package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
- package/dist/headless/components/layout/tabGroups/tabGroups.js +781 -0
- package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +199 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js +497 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
- package/dist/headless/components/navigation/appBar/appBar.js +35 -30
- package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/headless/components/navigation/commandPalette/commandPalette.js +335 -0
- package/dist/headless/components/navigation/commandPalette/commandPalette.js.map +1 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
- package/dist/headless/components/navigation/sidebar/sidebar.js +56 -54
- package/dist/headless/components/navigation/sidebar/sidebar.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tab/tab.js +121 -42
- package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js +25 -0
- package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
- package/dist/headless/components/navigation/tabs/tabs.js +369 -145
- package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabs.utils.js +11 -0
- package/dist/headless/components/navigation/tabs/tabs.utils.js.map +1 -0
- package/dist/headless/components/navigation/tabs/tabsContext.js +6 -0
- package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -0
- package/dist/headless/hooks/useFocusTrap.js +24 -21
- package/dist/headless/hooks/useFocusTrap.js.map +1 -1
- package/dist/headless/hooks/useKeyboardShortcut.js +19 -0
- package/dist/headless/hooks/useKeyboardShortcut.js.map +1 -0
- package/dist/headless/index.js +360 -316
- package/dist/headless/index.js.map +1 -1
- package/dist/headless/utils/keyboardShortcut.js +49 -0
- package/dist/headless/utils/keyboardShortcut.js.map +1 -0
- package/dist/headless/utils/linkAttrs.js +13 -0
- package/dist/headless/utils/linkAttrs.js.map +1 -0
- package/dist/headless/utils/restoreFocus.js +10 -0
- package/dist/headless/utils/restoreFocus.js.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +6 -1
- package/dist/hooks/useFocusTrap.js +24 -21
- package/dist/hooks/useFocusTrap.js.map +1 -1
- package/dist/hooks/useKeyboardShortcut.d.ts +30 -0
- package/dist/hooks/useKeyboardShortcut.js +19 -0
- package/dist/hooks/useKeyboardShortcut.js.map +1 -0
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +24 -3
- package/dist/index.js +360 -316
- package/dist/index.js.map +1 -1
- package/dist/utils/keyboardShortcut.d.ts +12 -0
- package/dist/utils/keyboardShortcut.js +49 -0
- package/dist/utils/keyboardShortcut.js.map +1 -0
- package/dist/utils/linkAttrs.d.ts +13 -0
- package/dist/utils/linkAttrs.js +13 -0
- package/dist/utils/linkAttrs.js.map +1 -0
- package/dist/utils/restoreFocus.d.ts +8 -0
- package/dist/utils/restoreFocus.js +10 -0
- package/dist/utils/restoreFocus.js.map +1 -0
- package/package.json +5 -3
|
@@ -1,80 +1,86 @@
|
|
|
1
|
-
import { jsx as
|
|
1
|
+
import { jsx as k, jsxs as y } from "react/jsx-runtime";
|
|
2
2
|
import '../../../assets/styles/less/components/button/button.entry.css';import '../../../assets/styles/less/tokens.entry.css';/* empty css */
|
|
3
3
|
/* empty css */
|
|
4
|
-
import
|
|
4
|
+
import x from "react";
|
|
5
5
|
import W from "clsx";
|
|
6
|
-
import { Ripple as
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import { Ripple as _ } from "../../base/ripple/ripple.js";
|
|
7
|
+
import { resolveLinkRel as q, resolveLinkTarget as A } from "../../../utils/linkAttrs.js";
|
|
8
|
+
import { Icon as F } from "../../base/icon/icon.js";
|
|
9
|
+
const V = x.forwardRef(
|
|
10
|
+
function(N, m) {
|
|
11
11
|
const {
|
|
12
|
-
label:
|
|
13
|
-
variant:
|
|
14
|
-
icon:
|
|
15
|
-
iconProps:
|
|
16
|
-
href:
|
|
12
|
+
label: n,
|
|
13
|
+
variant: $ = "contained",
|
|
14
|
+
icon: o,
|
|
15
|
+
iconProps: j = {},
|
|
16
|
+
href: c,
|
|
17
|
+
target: v,
|
|
18
|
+
rel: B,
|
|
17
19
|
className: D,
|
|
18
20
|
disabled: r,
|
|
19
|
-
children:
|
|
21
|
+
children: a,
|
|
20
22
|
onMouseDown: i,
|
|
21
23
|
// The button sets this on its root too; its own handler calls the caller's first.
|
|
22
24
|
onPointerDown: s,
|
|
23
25
|
fullWidth: E,
|
|
24
|
-
rippleCenter:
|
|
26
|
+
rippleCenter: L,
|
|
25
27
|
disableRipple: z,
|
|
26
28
|
size: C = "medium",
|
|
27
29
|
colorTheme: M = "primary",
|
|
28
30
|
color: l,
|
|
29
|
-
"data-testid":
|
|
30
|
-
...
|
|
31
|
-
} =
|
|
32
|
-
i == null || i(
|
|
33
|
-
}, d = (
|
|
34
|
-
var
|
|
35
|
-
s == null || s(
|
|
31
|
+
"data-testid": e,
|
|
32
|
+
...p
|
|
33
|
+
} = N, f = l != null ? l : M, u = x.useRef(null), b = (t) => {
|
|
34
|
+
i == null || i(t);
|
|
35
|
+
}, d = (t) => {
|
|
36
|
+
var g;
|
|
37
|
+
s == null || s(t), r || (g = u.current) == null || g.onRipple(t);
|
|
36
38
|
}, w = W(
|
|
37
39
|
"smwb-button",
|
|
38
|
-
`smwb-${
|
|
40
|
+
`smwb-${$}`,
|
|
39
41
|
`smwb-${C}`,
|
|
40
|
-
|
|
42
|
+
f === "primary" ? "smwb-primary" : `smwb-button_color-${f}`,
|
|
41
43
|
D,
|
|
42
44
|
{
|
|
43
45
|
"smwb-disabled": r,
|
|
44
46
|
"smwb-full-width": E
|
|
45
47
|
}
|
|
46
|
-
), R = !z && /* @__PURE__ */
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
48
|
+
), R = !z && /* @__PURE__ */ k(_, { actionRef: u, center: L }), h = typeof o == "string" ? /* @__PURE__ */ k(F, { ...j, name: o }) : o;
|
|
49
|
+
if (c) {
|
|
50
|
+
const t = A(v);
|
|
51
|
+
return /* @__PURE__ */ y(
|
|
52
|
+
"a",
|
|
53
|
+
{
|
|
54
|
+
"data-testid": e != null ? e : "button-link",
|
|
55
|
+
ref: m,
|
|
56
|
+
className: w,
|
|
57
|
+
href: c,
|
|
58
|
+
target: t,
|
|
59
|
+
rel: q(B, t),
|
|
60
|
+
onMouseDown: b,
|
|
61
|
+
onPointerDown: d,
|
|
62
|
+
...p,
|
|
63
|
+
children: [
|
|
64
|
+
o && h,
|
|
65
|
+
n || a,
|
|
66
|
+
R
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return /* @__PURE__ */ y(
|
|
66
72
|
"button",
|
|
67
73
|
{
|
|
68
|
-
"data-testid":
|
|
69
|
-
ref:
|
|
74
|
+
"data-testid": e != null ? e : "button",
|
|
75
|
+
ref: m,
|
|
70
76
|
className: w,
|
|
71
|
-
onMouseDown:
|
|
77
|
+
onMouseDown: b,
|
|
72
78
|
onPointerDown: d,
|
|
73
79
|
disabled: !!r,
|
|
74
|
-
...
|
|
80
|
+
...p,
|
|
75
81
|
children: [
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
o && h,
|
|
83
|
+
n || a,
|
|
78
84
|
R
|
|
79
85
|
]
|
|
80
86
|
}
|
|
@@ -82,7 +88,7 @@ const Q = g.forwardRef(
|
|
|
82
88
|
}
|
|
83
89
|
);
|
|
84
90
|
export {
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
V as Button,
|
|
92
|
+
V as default
|
|
87
93
|
};
|
|
88
94
|
//# sourceMappingURL=button.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","sources":["../../../../src/components/inputs/button/button.tsx"],"sourcesContent":["import React, { PropsWithChildren } from \"react\";\nimport cn from \"clsx\";\nimport { Ripple, RippleActionsRef } from \"../../base/ripple/ripple\";\nimport { Icon, IconProps } from \"../../base/icon\";\n\nexport interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement> {\n /**\n * Текст на кнопке.\n */\n label?: string;\n\n /**\n * Вариант стилизации кнопки.\n */\n variant?: \"contained\" | \"text\" | \"outlined\";\n\n /**\n * Размер кнопки.\n */\n size?: \"small\" | \"medium\" | \"large\";\n\n /**\n * Иконка, которая может быть ReactNode (например, <Icon/>) или строкой (url, base64, и т.д.).\n */\n icon?: React.ReactNode | string;\n\n /**\n * Пропсы для иконки (исключая 'name', если в IconProps оно обязательно).\n */\n iconProps?: Omit<IconProps, \"name\">;\n\n /**\n * @deprecated используйте `color`. Оставлено для обратной совместимости.\n */\n colorTheme?: \"primary\";\n\n /**\n * Семантический цвет кнопки. Резолвится через токены `--smui-*Color*`.\n */\n color?: \"primary\" | \"secondary\" | \"error\" | \"success\" | \"warning\" | \"info\";\n\n /**\n * Ссылка. Если задана, компонент
|
|
1
|
+
{"version":3,"file":"button.js","sources":["../../../../src/components/inputs/button/button.tsx"],"sourcesContent":["import React, { PropsWithChildren } from \"react\";\nimport cn from \"clsx\";\nimport { Ripple, RippleActionsRef } from \"../../base/ripple/ripple\";\nimport { Icon, IconProps } from \"../../base/icon\";\nimport { resolveLinkRel, resolveLinkTarget } from \"../../../utils/linkAttrs\";\n\nexport interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement> {\n /**\n * Текст на кнопке.\n */\n label?: string;\n\n /**\n * Вариант стилизации кнопки.\n */\n variant?: \"contained\" | \"text\" | \"outlined\";\n\n /**\n * Размер кнопки.\n */\n size?: \"small\" | \"medium\" | \"large\";\n\n /**\n * Иконка, которая может быть ReactNode (например, <Icon/>) или строкой (url, base64, и т.д.).\n */\n icon?: React.ReactNode | string;\n\n /**\n * Пропсы для иконки (исключая 'name', если в IconProps оно обязательно).\n */\n iconProps?: Omit<IconProps, \"name\">;\n\n /**\n * @deprecated используйте `color`. Оставлено для обратной совместимости.\n */\n colorTheme?: \"primary\";\n\n /**\n * Семантический цвет кнопки. Резолвится через токены `--smui-*Color*`.\n */\n color?: \"primary\" | \"secondary\" | \"error\" | \"success\" | \"warning\" | \"info\";\n\n /**\n * Ссылка. Если задана, компонент рендерится как <a>.\n */\n href?: string;\n\n /**\n * Where a link (with `href`) opens. By default `\"_blank\"`: a new tab. `null` leaves the `target`\n * attribute out, so the link opens in place, like an internal one; an empty string does the same, and\n * any other string is used as is.\n */\n target?: string | null;\n\n /**\n * The `rel` of a link (with `href`). By default `\"noreferrer\"` for a link that opens another tab or\n * window, and none for one that opens in place. Your own value replaces the default, so add `noreferrer` yourself\n * if you still want it; an empty string drops the attribute.\n */\n rel?: string;\n\n /**\n * Отключённое состояние.\n */\n disabled?: boolean;\n\n /**\n * Тип кнопки.\n */\n type?: \"button\" | \"submit\" | \"reset\";\n\n /**\n * Растягивать кнопку по всей ширине контейнера.\n */\n fullWidth?: boolean;\n\n /**\n * Позиция риппл-эффекта по центру.\n */\n rippleCenter?: boolean;\n\n /**\n * Отключить риппл-эффект.\n */\n disableRipple?: boolean;\n\n /** Test id of the root; `button`, or `button-link` for a link, unless given. */\n \"data-testid\"?: string;\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement, PropsWithChildren<ButtonProps>>(\n function Button(props, ref) {\n const {\n label,\n variant = \"contained\",\n icon,\n iconProps = {},\n href,\n target,\n rel,\n className,\n disabled,\n children,\n onMouseDown: onMouseDownProp,\n // The button sets this on its root too; its own handler calls the caller's first.\n onPointerDown: onPointerDownProp,\n fullWidth,\n rippleCenter,\n disableRipple,\n\n size = \"medium\",\n colorTheme = \"primary\",\n color: colorProp,\n \"data-testid\": dataTestId,\n ...rest\n } = props;\n const color = colorProp ?? colorTheme;\n const rippleRef = React.useRef<RippleActionsRef>(null);\n\n const onMouseDown = (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {\n onMouseDownProp?.(event);\n };\n\n // Ripple on pointerdown so it fires for touch and pen, not just mouse.\n const onPointerDown = (event: React.PointerEvent<HTMLButtonElement | HTMLAnchorElement>) => {\n onPointerDownProp?.(event);\n if (!disabled) {\n rippleRef.current?.onRipple(event);\n }\n };\n\n const classes = cn(\n \"smwb-button\",\n `smwb-${variant}`,\n `smwb-${size}`,\n color === \"primary\" ? \"smwb-primary\" : `smwb-button_color-${color}`,\n className,\n {\n \"smwb-disabled\": disabled,\n \"smwb-full-width\": fullWidth,\n }\n );\n\n const rippleElement = !disableRipple && <Ripple actionRef={rippleRef} center={rippleCenter} />;\n const iconElement = typeof icon === \"string\" ? <Icon {...iconProps} name={icon} /> : icon;\n\n if (href) {\n const linkTarget = resolveLinkTarget(target);\n return (\n <a\n data-testid={dataTestId ?? \"button-link\"}\n ref={ref as React.LegacyRef<HTMLAnchorElement>}\n className={classes}\n href={href}\n target={linkTarget}\n rel={resolveLinkRel(rel, linkTarget)}\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n {...rest}\n >\n {icon && iconElement}\n {label ? label : children}\n {rippleElement}\n </a>\n );\n }\n\n return (\n <button\n data-testid={dataTestId ?? \"button\"}\n ref={ref as React.LegacyRef<HTMLButtonElement>}\n className={classes}\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n disabled={!!disabled}\n {...rest}\n >\n {icon && iconElement}\n {label ? label : children}\n {rippleElement}\n </button>\n );\n }\n);\nexport default Button;\n"],"names":["Button","React","props","ref","label","variant","icon","iconProps","href","target","rel","className","disabled","children","onMouseDownProp","onPointerDownProp","fullWidth","rippleCenter","disableRipple","size","colorTheme","colorProp","dataTestId","rest","color","rippleRef","onMouseDown","event","onPointerDown","_a","classes","cn","rippleElement","jsx","Ripple","iconElement","Icon","linkTarget","resolveLinkTarget","jsxs","resolveLinkRel"],"mappings":";;;;;;;;AA4FO,MAAMA,IAASC,EAAM;AAAA,EAC1B,SAAgBC,GAAOC,GAAK;AAC1B,UAAM;AAAA,MACJ,OAAAC;AAAA,MACA,SAAAC,IAAU;AAAA,MACV,MAAAC;AAAA,MACA,WAAAC,IAAY,CAAA;AAAA,MACZ,MAAAC;AAAA,MACA,QAAAC;AAAA,MACA,KAAAC;AAAA,MACA,WAAAC;AAAA,MACA,UAAAC;AAAA,MACA,UAAAC;AAAA,MACA,aAAaC;AAAA;AAAA,MAEb,eAAeC;AAAA,MACf,WAAAC;AAAA,MACA,cAAAC;AAAA,MACA,eAAAC;AAAA,MAEA,MAAAC,IAAO;AAAA,MACP,YAAAC,IAAa;AAAA,MACb,OAAOC;AAAA,MACP,eAAeC;AAAA,MACf,GAAGC;AAAA,IAAA,IACDrB,GACEsB,IAAQH,KAAA,OAAAA,IAAaD,GACrBK,IAAYxB,EAAM,OAAyB,IAAI,GAE/CyB,IAAc,CAACC,MAAmE;AACtF,MAAAb,KAAA,QAAAA,EAAkBa;AAAA,IACpB,GAGMC,IAAgB,CAACD,MAAqE;;AAC1F,MAAAZ,KAAA,QAAAA,EAAoBY,IACff,MACHiB,IAAAJ,EAAU,YAAV,QAAAI,EAAmB,SAASF;AAAA,IAEhC,GAEMG,IAAUC;AAAA,MACd;AAAA,MACA,QAAQ1B,CAAO;AAAA,MACf,QAAQc,CAAI;AAAA,MACZK,MAAU,YAAY,iBAAiB,qBAAqBA,CAAK;AAAA,MACjEb;AAAA,MACA;AAAA,QACE,iBAAiBC;AAAA,QACjB,mBAAmBI;AAAA,MAAA;AAAA,IACrB,GAGIgB,IAAgB,CAACd,KAAiB,gBAAAe,EAACC,KAAO,WAAWT,GAAW,QAAQR,GAAc,GACtFkB,IAAc,OAAO7B,KAAS,WAAW,gBAAA2B,EAACG,KAAM,GAAG7B,GAAW,MAAMD,EAAA,CAAM,IAAKA;AAErF,QAAIE,GAAM;AACR,YAAM6B,IAAaC,EAAkB7B,CAAM;AAC3C,aACE,gBAAA8B;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,eAAajB,KAAA,OAAAA,IAAc;AAAA,UAC3B,KAAAnB;AAAA,UACA,WAAW2B;AAAA,UACX,MAAAtB;AAAA,UACA,QAAQ6B;AAAA,UACR,KAAKG,EAAe9B,GAAK2B,CAAU;AAAA,UACnC,aAAAX;AAAA,UACA,eAAAE;AAAA,UACC,GAAGL;AAAA,UAEH,UAAA;AAAA,YAAAjB,KAAQ6B;AAAA,YACR/B,KAAgBS;AAAA,YAChBmB;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAGP;AAEA,WACE,gBAAAO;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,eAAajB,KAAA,OAAAA,IAAc;AAAA,QAC3B,KAAAnB;AAAA,QACA,WAAW2B;AAAA,QACX,aAAAJ;AAAA,QACA,eAAAE;AAAA,QACA,UAAU,CAAC,CAAChB;AAAA,QACX,GAAGW;AAAA,QAEH,UAAA;AAAA,UAAAjB,KAAQ6B;AAAA,UACR/B,KAAgBS;AAAA,UAChBmB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { DropzoneAccept } from "../../../hooks/useDropzone";
|
|
3
|
+
import type { ComposerSendKey } from "./composerKeys";
|
|
4
|
+
/** Where the toolbar and the action sit: under the field (`stacked`) or in one row with it (`inline`). */
|
|
5
|
+
export type ComposerLayout = "stacked" | "inline";
|
|
6
|
+
export interface ComposerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange" | "defaultValue" | "onKeyDown" | "onFocus" | "onBlur" | "children"> {
|
|
7
|
+
/**
|
|
8
|
+
* Controlled text. The composer is controlled while this is not `undefined` (checked on every render); a parent
|
|
9
|
+
* that ignores `onValueChange` keeps the field showing this value.
|
|
10
|
+
*/
|
|
11
|
+
value?: string;
|
|
12
|
+
/** Initial text while uncontrolled. Defaults to an empty string. */
|
|
13
|
+
defaultValue?: string;
|
|
14
|
+
/** Called on every text change: typing, a newline, and the clear after a send. Called in both modes. */
|
|
15
|
+
onValueChange?: (value: string) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Called with the trimmed text when the user sends it: the send key (see `sendKey`) or a click on the action
|
|
18
|
+
* button. Nothing is called while sending is not allowed: no `onSend`, an empty or whitespace-only text, `disabled`,
|
|
19
|
+
* `readOnly`, `busy`, or a text over `maxLength`. Async work is shown with `busy`; the return value is ignored.
|
|
20
|
+
*/
|
|
21
|
+
onSend?: (text: string) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Which Enter sends. `"modEnter"` (default): Ctrl/⌘+Enter sends and Enter inserts a newline. `"enter"`: Enter sends,
|
|
24
|
+
* Shift+Enter inserts a newline, Ctrl/⌘+Enter sends too. An Enter that commits an IME composition never sends.
|
|
25
|
+
*/
|
|
26
|
+
sendKey?: ComposerSendKey;
|
|
27
|
+
/**
|
|
28
|
+
* Clear the text after `onSend`: the composer's own state while uncontrolled, `onValueChange("")` while controlled.
|
|
29
|
+
* Defaults to `true`.
|
|
30
|
+
*/
|
|
31
|
+
clearOnSend?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The agent is working: the action button turns into Stop and calls `onStop`, and the keys and the button do not
|
|
34
|
+
* send. The text stays editable. The composer never changes `busy` itself, the parent owns it.
|
|
35
|
+
*/
|
|
36
|
+
busy?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Called when Stop is pressed (click, Enter or Space on the button) while `busy` and not `disabled`. Without it the
|
|
39
|
+
* Stop button does nothing, so pass it whenever `busy` can be set.
|
|
40
|
+
*/
|
|
41
|
+
onStop?: () => void;
|
|
42
|
+
/** Placeholder of the textarea. It is not a name for the field, set `aria-label` or `aria-labelledby` as well. */
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Hard limit on the text (the native `maxlength` of the textarea, counted in UTF-16 units, so an emoji is 2).
|
|
46
|
+
* Turns the counter on.
|
|
47
|
+
*/
|
|
48
|
+
maxLength?: number;
|
|
49
|
+
/** Show the counter (`n / maxLength`, or `n` without `maxLength`). Defaults to `true` when `maxLength` is set. */
|
|
50
|
+
counter?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Text for the polite status region that announces how many characters are left. It is spoken only near the limit
|
|
53
|
+
* (within the larger of 10 characters and 10% of `maxLength`) and when the text is over it, with a negative
|
|
54
|
+
* `remaining`. Defaults to "N characters left" / "N characters over the limit".
|
|
55
|
+
*/
|
|
56
|
+
counterAnnouncement?: (remaining: number, maxLength: number) => string;
|
|
57
|
+
/** Height of the empty field in rows, and the `rows` of the textarea. Defaults to `1`. */
|
|
58
|
+
minRows?: number;
|
|
59
|
+
/** Rows the field grows to before it scrolls. Clamped to at least `minRows`. Defaults to `8`. */
|
|
60
|
+
maxRows?: number;
|
|
61
|
+
/**
|
|
62
|
+
* `"stacked"` (default): the field on top, a bar under it with the attach button, the toolbar, the counter and the
|
|
63
|
+
* action. `"inline"`: the attach button, the field, the counter and the action in one row, the toolbar (if any)
|
|
64
|
+
* in a row under it.
|
|
65
|
+
*/
|
|
66
|
+
layout?: ComposerLayout;
|
|
67
|
+
/**
|
|
68
|
+
* Slot under the field for chips and selectors (agent, model, mode, …). Drawn in every state. It is a plain `div`,
|
|
69
|
+
* not `role="toolbar"`: the content brings its own keyboard handling and disabled state.
|
|
70
|
+
*/
|
|
71
|
+
toolbar?: React.ReactNode;
|
|
72
|
+
/**
|
|
73
|
+
* Slot above the field for the app's file chips. The composer keeps no file state: the app lists what `onAttach`
|
|
74
|
+
* gave it here.
|
|
75
|
+
*/
|
|
76
|
+
attachments?: React.ReactNode;
|
|
77
|
+
/**
|
|
78
|
+
* Turns on the attach button, the hidden file input and the drop target (the whole composer). Called with the files
|
|
79
|
+
* of a pick or a drop that are left after `accept`, `multiple` and `maxFiles`, never with an empty list. Only a drag
|
|
80
|
+
* of files is taken: dragged text or a link still goes into the field.
|
|
81
|
+
*/
|
|
82
|
+
onAttach?: (files: File[]) => void;
|
|
83
|
+
/**
|
|
84
|
+
* Accepted file types, as a record of mime type to extensions or a raw `accept` string (`image/*`, `.pdf`, an exact
|
|
85
|
+
* mime type). It sets the picker's filter, and the files of a pick or a drop that do not match are left out.
|
|
86
|
+
*/
|
|
87
|
+
accept?: DropzoneAccept;
|
|
88
|
+
/** Allow several files per pick or drop. When `false` the picker takes one and a drop keeps the first. Defaults to `true`. */
|
|
89
|
+
multiple?: boolean;
|
|
90
|
+
/** Files beyond this number are dropped from a pick or a drop (counted after `accept`). */
|
|
91
|
+
maxFiles?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Whether `onAttach` also makes the composer a drop target for files. Set `false` when a parent already takes drops
|
|
94
|
+
* (a chat panel): the attach button and the picker stay, and a drop on the composer bubbles to the parent untouched.
|
|
95
|
+
* Defaults to `true`.
|
|
96
|
+
*/
|
|
97
|
+
dropTarget?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Disables the textarea, the attach button, the action button and the drop target. Toolbar content is the app's to
|
|
100
|
+
* disable.
|
|
101
|
+
*/
|
|
102
|
+
disabled?: boolean;
|
|
103
|
+
/** The textarea is `readonly`: sending is unavailable, Stop still works. */
|
|
104
|
+
readOnly?: boolean;
|
|
105
|
+
/** Focus the textarea on mount. */
|
|
106
|
+
autoFocus?: boolean;
|
|
107
|
+
/** Name of the textarea. */
|
|
108
|
+
name?: string;
|
|
109
|
+
/** Id of the textarea (the root keeps no id). Generated when not given. */
|
|
110
|
+
id?: string;
|
|
111
|
+
/** Accessible name of the textarea. Set this or `aria-labelledby`: a placeholder is not a name. */
|
|
112
|
+
"aria-label"?: string;
|
|
113
|
+
/** Id(s) of the element(s) that name the textarea. */
|
|
114
|
+
"aria-labelledby"?: string;
|
|
115
|
+
/** Id(s) that describe the textarea. They come first, the counter's id is appended. */
|
|
116
|
+
"aria-describedby"?: string;
|
|
117
|
+
/** Key handler of the textarea. It runs before the composer's own; if it calls `preventDefault()`, the composer does nothing for that key. */
|
|
118
|
+
onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>;
|
|
119
|
+
/** Focus handler of the textarea. */
|
|
120
|
+
onFocus?: React.FocusEventHandler<HTMLTextAreaElement>;
|
|
121
|
+
/** Blur handler of the textarea. */
|
|
122
|
+
onBlur?: React.FocusEventHandler<HTMLTextAreaElement>;
|
|
123
|
+
/** Ref of the textarea (the root takes the component's own `ref`). */
|
|
124
|
+
inputRef?: React.Ref<HTMLTextAreaElement>;
|
|
125
|
+
/** Accessible name of the action button while it sends. Defaults to "Send". */
|
|
126
|
+
sendLabel?: string;
|
|
127
|
+
/** Accessible name of the action button while `busy`. Defaults to "Stop". */
|
|
128
|
+
stopLabel?: string;
|
|
129
|
+
/** Accessible name of the attach button. Defaults to "Attach file". */
|
|
130
|
+
attachLabel?: string;
|
|
131
|
+
/**
|
|
132
|
+
* Class name(s) for the root `<div>`. `style`, `ref`, `data-*` attributes and every other HTML attribute or event
|
|
133
|
+
* handler go to the root too; the root's drag handlers run after yours.
|
|
134
|
+
*/
|
|
135
|
+
className?: string;
|
|
136
|
+
/** Test id of the root `<div>`. Defaults to `composer`; the parts inside have their own (`composer-input`, `composer-action`, …). */
|
|
137
|
+
"data-testid"?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* A task input: a multi-line field that grows from `minRows` to `maxRows`, a `toolbar` slot under it for chip
|
|
141
|
+
* selectors, a send button that becomes Stop while `busy`, keyboard send (Ctrl/⌘+Enter by default), an optional
|
|
142
|
+
* attach button and drop target, and a character counter.
|
|
143
|
+
*
|
|
144
|
+
* ```tsx
|
|
145
|
+
* <Composer aria-label="Task for the agent" onSend={(text) => run(text)} busy={running} onStop={cancel} />
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export declare const Composer: React.ForwardRefExoticComponent<ComposerProps & React.RefAttributes<HTMLDivElement>>;
|
|
149
|
+
export default Composer;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { jsxs as De, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import '../../../assets/styles/less/components/composer/composer.entry.css';import '../../../assets/styles/less/tokens.entry.css';/* empty css */
|
|
3
|
+
/* empty css */
|
|
4
|
+
import A, { useState as Ce } from "react";
|
|
5
|
+
import L from "clsx";
|
|
6
|
+
import { Icon as H } from "../../base/icon/icon.js";
|
|
7
|
+
import { useControllableState as xe } from "../../../hooks/useControllableState.js";
|
|
8
|
+
import { useDropzone as Ke } from "../../../hooks/useDropzone.js";
|
|
9
|
+
import { useId as Ne } from "../../../hooks/useId.js";
|
|
10
|
+
import { filterAttachedFiles as Le, isFileDrag as V } from "./composerFiles.js";
|
|
11
|
+
import { resolveComposerKeyAction as Ae } from "./composerKeys.js";
|
|
12
|
+
const ke = (o) => o >= 0 ? `${o} characters left` : `${-o} characters over the limit`;
|
|
13
|
+
function Te(o) {
|
|
14
|
+
o.preventDefault();
|
|
15
|
+
}
|
|
16
|
+
function b(o) {
|
|
17
|
+
return Array.isArray(o) ? o.some(b) : A.isValidElement(o) && o.type === A.Fragment ? b(o.props.children) : o != null && typeof o != "boolean" && o !== "";
|
|
18
|
+
}
|
|
19
|
+
const qe = A.forwardRef(function(q, G) {
|
|
20
|
+
const {
|
|
21
|
+
value: J,
|
|
22
|
+
defaultValue: f,
|
|
23
|
+
onValueChange: Q,
|
|
24
|
+
onSend: h,
|
|
25
|
+
sendKey: U = "modEnter",
|
|
26
|
+
clearOnSend: W = !0,
|
|
27
|
+
busy: r = !1,
|
|
28
|
+
onStop: y,
|
|
29
|
+
placeholder: X,
|
|
30
|
+
maxLength: a,
|
|
31
|
+
counter: g,
|
|
32
|
+
counterAnnouncement: Y = ke,
|
|
33
|
+
minRows: w = 1,
|
|
34
|
+
maxRows: Z = 8,
|
|
35
|
+
layout: ee = "stacked",
|
|
36
|
+
toolbar: k,
|
|
37
|
+
attachments: T,
|
|
38
|
+
onAttach: i,
|
|
39
|
+
accept: S,
|
|
40
|
+
multiple: F = !0,
|
|
41
|
+
maxFiles: oe,
|
|
42
|
+
dropTarget: te = !0,
|
|
43
|
+
disabled: n = !1,
|
|
44
|
+
readOnly: R = !1,
|
|
45
|
+
autoFocus: ae,
|
|
46
|
+
name: re,
|
|
47
|
+
id: se,
|
|
48
|
+
"aria-label": ne,
|
|
49
|
+
"aria-labelledby": ie,
|
|
50
|
+
"aria-describedby": ce,
|
|
51
|
+
onKeyDown: _,
|
|
52
|
+
onFocus: v,
|
|
53
|
+
onBlur: D,
|
|
54
|
+
inputRef: le,
|
|
55
|
+
sendLabel: me = "Send",
|
|
56
|
+
stopLabel: de = "Stop",
|
|
57
|
+
attachLabel: pe = "Attach file",
|
|
58
|
+
className: ue,
|
|
59
|
+
"data-testid": C,
|
|
60
|
+
onDragOver: c,
|
|
61
|
+
onDragLeave: l,
|
|
62
|
+
onDrop: m,
|
|
63
|
+
...be
|
|
64
|
+
} = q, [s, $] = xe({
|
|
65
|
+
value: J,
|
|
66
|
+
defaultValue: f != null ? f : "",
|
|
67
|
+
onChange: Q
|
|
68
|
+
}), [fe, M] = Ce(!1), O = Ne(se, "smwb-composer"), z = `${O}-counter`, d = Ke({
|
|
69
|
+
accept: S,
|
|
70
|
+
multiple: F,
|
|
71
|
+
disabled: n,
|
|
72
|
+
// `maxFiles` is not passed on: the cut has to come after `accept`, see `filterAttachedFiles`.
|
|
73
|
+
onDrop: (e) => {
|
|
74
|
+
const N = Le(e, { accept: S, multiple: F, maxFiles: oe });
|
|
75
|
+
N.length > 0 && (i == null || i(N));
|
|
76
|
+
}
|
|
77
|
+
}), x = d.getRootProps(), B = d.getInputProps(), K = i !== void 0, I = K && te, p = g != null ? g : a !== void 0, u = a !== void 0 && s.length > a, P = !!h && s.trim() !== "" && !n && !R && !r && !u;
|
|
78
|
+
let j = "";
|
|
79
|
+
if (p && a !== void 0) {
|
|
80
|
+
const e = a - s.length;
|
|
81
|
+
e <= Math.max(10, Math.ceil(a * 0.1)) && (j = Y(e, a));
|
|
82
|
+
}
|
|
83
|
+
const E = () => {
|
|
84
|
+
!P || !h || (h(s.trim()), W && $(""));
|
|
85
|
+
}, he = (e) => {
|
|
86
|
+
_ == null || _(e), !(e.defaultPrevented || Ae(
|
|
87
|
+
{
|
|
88
|
+
key: e.key,
|
|
89
|
+
shiftKey: e.shiftKey,
|
|
90
|
+
ctrlKey: e.ctrlKey,
|
|
91
|
+
metaKey: e.metaKey,
|
|
92
|
+
altKey: e.altKey,
|
|
93
|
+
isComposing: e.nativeEvent.isComposing,
|
|
94
|
+
keyCode: e.keyCode
|
|
95
|
+
},
|
|
96
|
+
U
|
|
97
|
+
) === "native") && (e.preventDefault(), E());
|
|
98
|
+
}, ye = (e) => {
|
|
99
|
+
if (!(e.detail > 1)) {
|
|
100
|
+
if (r) {
|
|
101
|
+
n || y == null || y();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
E();
|
|
105
|
+
}
|
|
106
|
+
}, ge = I ? { onDragOver: (e) => {
|
|
107
|
+
c == null || c(e), V(e.dataTransfer) && x.onDragOver(e);
|
|
108
|
+
}, onDragLeave: (e) => {
|
|
109
|
+
l == null || l(e), !(e.relatedTarget instanceof Node && e.currentTarget.contains(e.relatedTarget)) && x.onDragLeave();
|
|
110
|
+
}, onDrop: (e) => {
|
|
111
|
+
m == null || m(e), V(e.dataTransfer) && x.onDrop(e);
|
|
112
|
+
} } : { onDragOver: c, onDragLeave: l, onDrop: m }, we = I && d.isDragActive, _e = {
|
|
113
|
+
"--smwb-composer-min-rows": w,
|
|
114
|
+
"--smwb-composer-max-rows": Math.max(Z, w)
|
|
115
|
+
}, ve = [ce, p ? z : void 0].filter(Boolean).join(" ") || void 0;
|
|
116
|
+
return /* @__PURE__ */ De(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
...be,
|
|
120
|
+
...ge,
|
|
121
|
+
ref: G,
|
|
122
|
+
className: L(
|
|
123
|
+
"smwb-composer",
|
|
124
|
+
`smwb-composer_${ee}`,
|
|
125
|
+
fe && "smwb-composer_focused",
|
|
126
|
+
r && "smwb-composer_busy",
|
|
127
|
+
n && "smwb-composer_disabled",
|
|
128
|
+
we && "smwb-composer_drag-active",
|
|
129
|
+
u && "smwb-composer_over-limit",
|
|
130
|
+
ue
|
|
131
|
+
),
|
|
132
|
+
"data-testid": C != null ? C : "composer",
|
|
133
|
+
children: [
|
|
134
|
+
b(T) ? /* @__PURE__ */ t("div", { className: "smwb-composer__attachments", "data-testid": "composer-attachments", children: T }) : null,
|
|
135
|
+
/* @__PURE__ */ t("div", { className: "smwb-composer__field", "data-value": s, style: _e, children: /* @__PURE__ */ t(
|
|
136
|
+
"textarea",
|
|
137
|
+
{
|
|
138
|
+
ref: le,
|
|
139
|
+
className: "smwb-composer__input",
|
|
140
|
+
id: O,
|
|
141
|
+
name: re,
|
|
142
|
+
rows: w,
|
|
143
|
+
placeholder: X,
|
|
144
|
+
maxLength: a,
|
|
145
|
+
disabled: n,
|
|
146
|
+
readOnly: R,
|
|
147
|
+
autoFocus: ae,
|
|
148
|
+
"aria-label": ne,
|
|
149
|
+
"aria-labelledby": ie,
|
|
150
|
+
"aria-describedby": ve,
|
|
151
|
+
"aria-invalid": u || void 0,
|
|
152
|
+
value: s,
|
|
153
|
+
onChange: (e) => $(e.target.value),
|
|
154
|
+
onKeyDown: he,
|
|
155
|
+
onFocus: (e) => {
|
|
156
|
+
v == null || v(e), M(!0);
|
|
157
|
+
},
|
|
158
|
+
onBlur: (e) => {
|
|
159
|
+
D == null || D(e), M(!1);
|
|
160
|
+
},
|
|
161
|
+
"data-testid": "composer-input"
|
|
162
|
+
}
|
|
163
|
+
) }),
|
|
164
|
+
K ? /* @__PURE__ */ t(
|
|
165
|
+
"button",
|
|
166
|
+
{
|
|
167
|
+
type: "button",
|
|
168
|
+
className: "smwb-composer__icon-button smwb-composer__attach",
|
|
169
|
+
"aria-label": pe,
|
|
170
|
+
disabled: n,
|
|
171
|
+
onClick: d.open,
|
|
172
|
+
"data-testid": "composer-attach",
|
|
173
|
+
children: /* @__PURE__ */ t(H, { name: "attach_file", size: 20 })
|
|
174
|
+
}
|
|
175
|
+
) : null,
|
|
176
|
+
b(k) ? /* @__PURE__ */ t("div", { className: "smwb-composer__toolbar", "data-testid": "composer-toolbar", children: k }) : null,
|
|
177
|
+
p ? /* @__PURE__ */ t(
|
|
178
|
+
"span",
|
|
179
|
+
{
|
|
180
|
+
id: z,
|
|
181
|
+
className: L("smwb-composer__counter", u && "smwb-composer__counter_error"),
|
|
182
|
+
"data-testid": "composer-counter",
|
|
183
|
+
children: a !== void 0 ? `${s.length} / ${a}` : s.length
|
|
184
|
+
}
|
|
185
|
+
) : null,
|
|
186
|
+
/* @__PURE__ */ t(
|
|
187
|
+
"button",
|
|
188
|
+
{
|
|
189
|
+
type: "button",
|
|
190
|
+
className: L("smwb-composer__icon-button", "smwb-composer__action", r && "smwb-composer__action_stop"),
|
|
191
|
+
"aria-label": r ? de : me,
|
|
192
|
+
"aria-disabled": !r && !P ? !0 : void 0,
|
|
193
|
+
disabled: n,
|
|
194
|
+
"data-action": r ? "stop" : "send",
|
|
195
|
+
onMouseDown: Te,
|
|
196
|
+
onClick: ye,
|
|
197
|
+
"data-testid": "composer-action",
|
|
198
|
+
children: /* @__PURE__ */ t(H, { name: r ? "stop" : "send", size: 20 })
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
p ? /* @__PURE__ */ t("span", { className: "smwb-composer__status", role: "status", "data-testid": "composer-status", children: j }) : null,
|
|
202
|
+
K ? /* @__PURE__ */ t(
|
|
203
|
+
"input",
|
|
204
|
+
{
|
|
205
|
+
...B,
|
|
206
|
+
onChange: (e) => {
|
|
207
|
+
B.onChange(e), e.currentTarget.value = "";
|
|
208
|
+
},
|
|
209
|
+
"data-testid": "composer-file-input"
|
|
210
|
+
}
|
|
211
|
+
) : null
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
export {
|
|
217
|
+
qe as Composer
|
|
218
|
+
};
|
|
219
|
+
//# sourceMappingURL=composer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer.js","sources":["../../../../src/components/inputs/composer/composer.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport cn from \"clsx\";\nimport Icon from \"../../base/icon/icon\";\nimport { useControllableState } from \"../../../hooks/useControllableState\";\nimport { useDropzone } from \"../../../hooks/useDropzone\";\nimport type { DropzoneAccept } from \"../../../hooks/useDropzone\";\nimport { useId } from \"../../../hooks/useId\";\nimport { filterAttachedFiles, isFileDrag } from \"./composerFiles\";\nimport { resolveComposerKeyAction } from \"./composerKeys\";\nimport type { ComposerSendKey } from \"./composerKeys\";\n\n/** Where the toolbar and the action sit: under the field (`stacked`) or in one row with it (`inline`). */\nexport type ComposerLayout = \"stacked\" | \"inline\";\n\nexport interface ComposerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n \"onChange\" | \"defaultValue\" | \"onKeyDown\" | \"onFocus\" | \"onBlur\" | \"children\"\n> {\n /**\n * Controlled text. The composer is controlled while this is not `undefined` (checked on every render); a parent\n * that ignores `onValueChange` keeps the field showing this value.\n */\n value?: string;\n /** Initial text while uncontrolled. Defaults to an empty string. */\n defaultValue?: string;\n /** Called on every text change: typing, a newline, and the clear after a send. Called in both modes. */\n onValueChange?: (value: string) => void;\n /**\n * Called with the trimmed text when the user sends it: the send key (see `sendKey`) or a click on the action\n * button. Nothing is called while sending is not allowed: no `onSend`, an empty or whitespace-only text, `disabled`,\n * `readOnly`, `busy`, or a text over `maxLength`. Async work is shown with `busy`; the return value is ignored.\n */\n onSend?: (text: string) => void;\n /**\n * Which Enter sends. `\"modEnter\"` (default): Ctrl/⌘+Enter sends and Enter inserts a newline. `\"enter\"`: Enter sends,\n * Shift+Enter inserts a newline, Ctrl/⌘+Enter sends too. An Enter that commits an IME composition never sends.\n */\n sendKey?: ComposerSendKey;\n /**\n * Clear the text after `onSend`: the composer's own state while uncontrolled, `onValueChange(\"\")` while controlled.\n * Defaults to `true`.\n */\n clearOnSend?: boolean;\n /**\n * The agent is working: the action button turns into Stop and calls `onStop`, and the keys and the button do not\n * send. The text stays editable. The composer never changes `busy` itself, the parent owns it.\n */\n busy?: boolean;\n /**\n * Called when Stop is pressed (click, Enter or Space on the button) while `busy` and not `disabled`. Without it the\n * Stop button does nothing, so pass it whenever `busy` can be set.\n */\n onStop?: () => void;\n /** Placeholder of the textarea. It is not a name for the field, set `aria-label` or `aria-labelledby` as well. */\n placeholder?: string;\n /**\n * Hard limit on the text (the native `maxlength` of the textarea, counted in UTF-16 units, so an emoji is 2).\n * Turns the counter on.\n */\n maxLength?: number;\n /** Show the counter (`n / maxLength`, or `n` without `maxLength`). Defaults to `true` when `maxLength` is set. */\n counter?: boolean;\n /**\n * Text for the polite status region that announces how many characters are left. It is spoken only near the limit\n * (within the larger of 10 characters and 10% of `maxLength`) and when the text is over it, with a negative\n * `remaining`. Defaults to \"N characters left\" / \"N characters over the limit\".\n */\n counterAnnouncement?: (remaining: number, maxLength: number) => string;\n /** Height of the empty field in rows, and the `rows` of the textarea. Defaults to `1`. */\n minRows?: number;\n /** Rows the field grows to before it scrolls. Clamped to at least `minRows`. Defaults to `8`. */\n maxRows?: number;\n /**\n * `\"stacked\"` (default): the field on top, a bar under it with the attach button, the toolbar, the counter and the\n * action. `\"inline\"`: the attach button, the field, the counter and the action in one row, the toolbar (if any)\n * in a row under it.\n */\n layout?: ComposerLayout;\n /**\n * Slot under the field for chips and selectors (agent, model, mode, …). Drawn in every state. It is a plain `div`,\n * not `role=\"toolbar\"`: the content brings its own keyboard handling and disabled state.\n */\n toolbar?: React.ReactNode;\n /**\n * Slot above the field for the app's file chips. The composer keeps no file state: the app lists what `onAttach`\n * gave it here.\n */\n attachments?: React.ReactNode;\n /**\n * Turns on the attach button, the hidden file input and the drop target (the whole composer). Called with the files\n * of a pick or a drop that are left after `accept`, `multiple` and `maxFiles`, never with an empty list. Only a drag\n * of files is taken: dragged text or a link still goes into the field.\n */\n onAttach?: (files: File[]) => void;\n /**\n * Accepted file types, as a record of mime type to extensions or a raw `accept` string (`image/*`, `.pdf`, an exact\n * mime type). It sets the picker's filter, and the files of a pick or a drop that do not match are left out.\n */\n accept?: DropzoneAccept;\n /** Allow several files per pick or drop. When `false` the picker takes one and a drop keeps the first. Defaults to `true`. */\n multiple?: boolean;\n /** Files beyond this number are dropped from a pick or a drop (counted after `accept`). */\n maxFiles?: number;\n /**\n * Whether `onAttach` also makes the composer a drop target for files. Set `false` when a parent already takes drops\n * (a chat panel): the attach button and the picker stay, and a drop on the composer bubbles to the parent untouched.\n * Defaults to `true`.\n */\n dropTarget?: boolean;\n /**\n * Disables the textarea, the attach button, the action button and the drop target. Toolbar content is the app's to\n * disable.\n */\n disabled?: boolean;\n /** The textarea is `readonly`: sending is unavailable, Stop still works. */\n readOnly?: boolean;\n /** Focus the textarea on mount. */\n autoFocus?: boolean;\n /** Name of the textarea. */\n name?: string;\n /** Id of the textarea (the root keeps no id). Generated when not given. */\n id?: string;\n /** Accessible name of the textarea. Set this or `aria-labelledby`: a placeholder is not a name. */\n \"aria-label\"?: string;\n /** Id(s) of the element(s) that name the textarea. */\n \"aria-labelledby\"?: string;\n /** Id(s) that describe the textarea. They come first, the counter's id is appended. */\n \"aria-describedby\"?: string;\n /** Key handler of the textarea. It runs before the composer's own; if it calls `preventDefault()`, the composer does nothing for that key. */\n onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>;\n /** Focus handler of the textarea. */\n onFocus?: React.FocusEventHandler<HTMLTextAreaElement>;\n /** Blur handler of the textarea. */\n onBlur?: React.FocusEventHandler<HTMLTextAreaElement>;\n /** Ref of the textarea (the root takes the component's own `ref`). */\n inputRef?: React.Ref<HTMLTextAreaElement>;\n /** Accessible name of the action button while it sends. Defaults to \"Send\". */\n sendLabel?: string;\n /** Accessible name of the action button while `busy`. Defaults to \"Stop\". */\n stopLabel?: string;\n /** Accessible name of the attach button. Defaults to \"Attach file\". */\n attachLabel?: string;\n /**\n * Class name(s) for the root `<div>`. `style`, `ref`, `data-*` attributes and every other HTML attribute or event\n * handler go to the root too; the root's drag handlers run after yours.\n */\n className?: string;\n /** Test id of the root `<div>`. Defaults to `composer`; the parts inside have their own (`composer-input`, `composer-action`, …). */\n \"data-testid\"?: string;\n}\n\nconst defaultCounterAnnouncement = (remaining: number): string =>\n remaining >= 0 ? `${remaining} characters left` : `${-remaining} characters over the limit`;\n\nfunction stopMouseDown(event: React.MouseEvent<HTMLElement>): void {\n // Keeps the focus in the textarea when the action button is clicked with a mouse.\n event.preventDefault();\n}\n\n// Whether a slot draws anything: null, false, \"\" and empty arrays or fragments do not.\nfunction isDrawn(node: React.ReactNode): boolean {\n if (Array.isArray(node)) return node.some(isDrawn);\n if (React.isValidElement<{ children?: React.ReactNode }>(node) && node.type === React.Fragment) {\n return isDrawn(node.props.children);\n }\n return node != null && typeof node !== \"boolean\" && node !== \"\";\n}\n\n/**\n * A task input: a multi-line field that grows from `minRows` to `maxRows`, a `toolbar` slot under it for chip\n * selectors, a send button that becomes Stop while `busy`, keyboard send (Ctrl/⌘+Enter by default), an optional\n * attach button and drop target, and a character counter.\n *\n * ```tsx\n * <Composer aria-label=\"Task for the agent\" onSend={(text) => run(text)} busy={running} onStop={cancel} />\n * ```\n */\nexport const Composer = React.forwardRef<HTMLDivElement, ComposerProps>(function Composer(props, ref) {\n const {\n value,\n defaultValue,\n onValueChange,\n onSend,\n sendKey = \"modEnter\",\n clearOnSend = true,\n busy = false,\n onStop,\n placeholder,\n maxLength,\n counter,\n counterAnnouncement = defaultCounterAnnouncement,\n minRows = 1,\n maxRows = 8,\n layout = \"stacked\",\n toolbar,\n attachments,\n onAttach,\n accept,\n multiple = true,\n maxFiles,\n dropTarget = true,\n disabled = false,\n readOnly = false,\n autoFocus,\n name,\n id,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n onKeyDown,\n onFocus,\n onBlur,\n inputRef,\n sendLabel = \"Send\",\n stopLabel = \"Stop\",\n attachLabel = \"Attach file\",\n className,\n \"data-testid\": testId,\n onDragOver,\n onDragLeave,\n onDrop,\n ...rest\n } = props;\n\n const [text, setText] = useControllableState<string>({\n value,\n defaultValue: defaultValue ?? \"\",\n onChange: onValueChange,\n });\n const [focused, setFocused] = useState(false);\n const textareaId = useId(id, \"smwb-composer\");\n const counterId = `${textareaId}-counter`;\n\n const dropzone = useDropzone({\n accept,\n multiple,\n disabled,\n // `maxFiles` is not passed on: the cut has to come after `accept`, see `filterAttachedFiles`.\n onDrop: (files) => {\n const attached = filterAttachedFiles(files, { accept, multiple, maxFiles });\n if (attached.length > 0) onAttach?.(attached);\n },\n });\n const dropHandlers = dropzone.getRootProps();\n const inputProps = dropzone.getInputProps();\n\n const attachable = onAttach !== undefined;\n // `dropTarget={false}` keeps the attach button and the picker but hands drops to a parent that owns the target.\n const dropping = attachable && dropTarget;\n\n const showCounter = counter ?? maxLength !== undefined;\n const overLimit = maxLength !== undefined && text.length > maxLength;\n const canSend = !!onSend && text.trim() !== \"\" && !disabled && !readOnly && !busy && !overLimit;\n\n let status = \"\";\n if (showCounter && maxLength !== undefined) {\n const remaining = maxLength - text.length;\n if (remaining <= Math.max(10, Math.ceil(maxLength * 0.1))) status = counterAnnouncement(remaining, maxLength);\n }\n\n const send = () => {\n if (!canSend || !onSend) return;\n onSend(text.trim());\n if (clearOnSend) setText(\"\");\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n\n const action = resolveComposerKeyAction(\n {\n key: event.key,\n shiftKey: event.shiftKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n altKey: event.altKey,\n isComposing: event.nativeEvent.isComposing,\n keyCode: event.keyCode,\n },\n sendKey\n );\n if (action === \"native\") return;\n\n event.preventDefault();\n send();\n };\n\n const handleActionClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n // The second click of a double-click lands on the node the first one turned into the other action (Send into\n // Stop once the parent sets `busy`). It is not a new press: keyboard activation has `detail` 0, a click 1.\n if (event.detail > 1) return;\n if (busy) {\n if (!disabled) onStop?.();\n return;\n }\n send();\n };\n\n const rootDragOver = (event: React.DragEvent<HTMLDivElement>) => {\n onDragOver?.(event);\n // Only a drag of files is the dropzone's. Text or a link keeps its default: the textarea inserts it.\n if (isFileDrag(event.dataTransfer)) dropHandlers.onDragOver(event);\n };\n const rootDragLeave = (event: React.DragEvent<HTMLDivElement>) => {\n onDragLeave?.(event);\n // A leave onto a descendant is not a leave: it would flicker the drag-active state over the toolbar chips.\n if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) return;\n dropHandlers.onDragLeave();\n };\n const rootDrop = (event: React.DragEvent<HTMLDivElement>) => {\n onDrop?.(event);\n if (isFileDrag(event.dataTransfer)) dropHandlers.onDrop(event);\n };\n const dragHandlers = dropping\n ? { onDragOver: rootDragOver, onDragLeave: rootDragLeave, onDrop: rootDrop }\n : { onDragOver, onDragLeave, onDrop };\n\n const dragActive = dropping && dropzone.isDragActive;\n const fieldStyle = {\n \"--smwb-composer-min-rows\": minRows,\n \"--smwb-composer-max-rows\": Math.max(maxRows, minRows),\n } as React.CSSProperties;\n const describedBy = [ariaDescribedBy, showCounter ? counterId : undefined].filter(Boolean).join(\" \") || undefined;\n\n return (\n <div\n {...rest}\n {...dragHandlers}\n ref={ref}\n className={cn(\n \"smwb-composer\",\n `smwb-composer_${layout}`,\n focused && \"smwb-composer_focused\",\n busy && \"smwb-composer_busy\",\n disabled && \"smwb-composer_disabled\",\n dragActive && \"smwb-composer_drag-active\",\n overLimit && \"smwb-composer_over-limit\",\n className\n )}\n data-testid={testId ?? \"composer\"}\n >\n {isDrawn(attachments) ? (\n <div className=\"smwb-composer__attachments\" data-testid=\"composer-attachments\">\n {attachments}\n </div>\n ) : null}\n <div className=\"smwb-composer__field\" data-value={text} style={fieldStyle}>\n <textarea\n ref={inputRef}\n className=\"smwb-composer__input\"\n id={textareaId}\n name={name}\n rows={minRows}\n placeholder={placeholder}\n maxLength={maxLength}\n disabled={disabled}\n readOnly={readOnly}\n autoFocus={autoFocus}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={describedBy}\n aria-invalid={overLimit || undefined}\n value={text}\n onChange={(event) => setText(event.target.value)}\n onKeyDown={handleKeyDown}\n onFocus={(event) => {\n onFocus?.(event);\n setFocused(true);\n }}\n onBlur={(event) => {\n onBlur?.(event);\n setFocused(false);\n }}\n data-testid=\"composer-input\"\n />\n </div>\n {attachable ? (\n <button\n type=\"button\"\n className=\"smwb-composer__icon-button smwb-composer__attach\"\n aria-label={attachLabel}\n disabled={disabled}\n onClick={dropzone.open}\n data-testid=\"composer-attach\"\n >\n <Icon name=\"attach_file\" size={20} />\n </button>\n ) : null}\n {isDrawn(toolbar) ? (\n <div className=\"smwb-composer__toolbar\" data-testid=\"composer-toolbar\">\n {toolbar}\n </div>\n ) : null}\n {showCounter ? (\n <span\n id={counterId}\n className={cn(\"smwb-composer__counter\", overLimit && \"smwb-composer__counter_error\")}\n data-testid=\"composer-counter\"\n >\n {maxLength !== undefined ? `${text.length} / ${maxLength}` : text.length}\n </span>\n ) : null}\n <button\n type=\"button\"\n className={cn(\"smwb-composer__icon-button\", \"smwb-composer__action\", busy && \"smwb-composer__action_stop\")}\n aria-label={busy ? stopLabel : sendLabel}\n aria-disabled={!busy && !canSend ? true : undefined}\n disabled={disabled}\n data-action={busy ? \"stop\" : \"send\"}\n onMouseDown={stopMouseDown}\n onClick={handleActionClick}\n data-testid=\"composer-action\"\n >\n <Icon name={busy ? \"stop\" : \"send\"} size={20} />\n </button>\n {showCounter ? (\n <span className=\"smwb-composer__status\" role=\"status\" data-testid=\"composer-status\">\n {status}\n </span>\n ) : null}\n {attachable ? (\n <input\n {...inputProps}\n onChange={(event) => {\n inputProps.onChange(event);\n // Lets the same file be picked again.\n event.currentTarget.value = \"\";\n }}\n data-testid=\"composer-file-input\"\n />\n ) : null}\n </div>\n );\n});\n\nexport default Composer;\n"],"names":["defaultCounterAnnouncement","remaining","stopMouseDown","event","isDrawn","node","React","Composer","props","ref","value","defaultValue","onValueChange","onSend","sendKey","clearOnSend","busy","onStop","placeholder","maxLength","counter","counterAnnouncement","minRows","maxRows","layout","toolbar","attachments","onAttach","accept","multiple","maxFiles","dropTarget","disabled","readOnly","autoFocus","name","id","ariaLabel","ariaLabelledBy","ariaDescribedBy","onKeyDown","onFocus","onBlur","inputRef","sendLabel","stopLabel","attachLabel","className","testId","onDragOver","onDragLeave","onDrop","rest","text","setText","useControllableState","focused","setFocused","useState","textareaId","useId","counterId","dropzone","useDropzone","files","attached","filterAttachedFiles","dropHandlers","inputProps","attachable","dropping","showCounter","overLimit","canSend","status","send","handleKeyDown","resolveComposerKeyAction","handleActionClick","dragHandlers","isFileDrag","dragActive","fieldStyle","describedBy","jsxs","cn","jsx","Icon"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Accepted file types as `Composer` takes them: a record of mime type to extensions, or a raw `accept` string. */
|
|
2
|
+
export type ComposerAccept = Record<string, string[]> | string;
|
|
3
|
+
/** The part of a `DataTransfer` the drag guard reads. */
|
|
4
|
+
export interface ComposerDragData {
|
|
5
|
+
types?: ArrayLike<string> | null | undefined;
|
|
6
|
+
files?: ArrayLike<unknown> | null | undefined;
|
|
7
|
+
}
|
|
8
|
+
/** The options that decide which of the picked or dropped files `Composer` passes on. */
|
|
9
|
+
export interface ComposerFileOptions {
|
|
10
|
+
accept?: ComposerAccept | undefined;
|
|
11
|
+
multiple?: boolean | undefined;
|
|
12
|
+
maxFiles?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Whether a drag carries files. A text or link drag does not and stays with the browser (the textarea inserts it).
|
|
16
|
+
* `dragover` exposes only `types`, and Firefox gives a `DOMStringList` there, hence `Array.from`; a `drop` has the
|
|
17
|
+
* file list as well.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isFileDrag(data: ComposerDragData | null | undefined): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The files of a pick or a drop that `Composer` passes to `onAttach`: those that match `accept` (a drop is not
|
|
22
|
+
* filtered by the browser, and the picker's "All files" choice lifts its filter), cut to one file when `multiple` is
|
|
23
|
+
* `false`, then to `maxFiles`. The cut comes last, so the files it drops are the ones past the limit, not the ones
|
|
24
|
+
* `accept` would have refused anyway.
|
|
25
|
+
*/
|
|
26
|
+
export declare function filterAttachedFiles(files: File[], options: ComposerFileOptions): File[];
|