@djangocfg/widget-chat 0.1.12 → 0.1.14
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/package.json +9 -9
- package/src/composer/field/input.tsx +22 -2
- package/src/styles/composer.css +41 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/widget-chat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "A transport-agnostic chat surface: a pure core, a store, primitives, a composer, and the assembled components a host mounts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chat",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"test:watch": "vitest"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@djangocfg/widget-kit": "^0.1.
|
|
58
|
+
"@djangocfg/widget-kit": "^0.1.15",
|
|
59
59
|
"@djangocfg/widget-media": "^0.1.9",
|
|
60
60
|
"@streamdown/code": "^1.1.1",
|
|
61
61
|
"@streamdown/math": "^1.0.2",
|
|
@@ -66,19 +66,19 @@
|
|
|
66
66
|
"use-stick-to-bottom": "^1.1.6"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@djangocfg/api": "^2.1.
|
|
70
|
-
"@djangocfg/i18n": "^2.1.
|
|
71
|
-
"@djangocfg/ui-core": "^2.1.
|
|
69
|
+
"@djangocfg/api": "^2.1.585",
|
|
70
|
+
"@djangocfg/i18n": "^2.1.585",
|
|
71
|
+
"@djangocfg/ui-core": "^2.1.585",
|
|
72
72
|
"lucide-react": "^0.545.0",
|
|
73
73
|
"react": "^19.0.0",
|
|
74
74
|
"remark-gfm": "^4.0.0",
|
|
75
75
|
"streamdown": "^2.6.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@djangocfg/api": "^2.1.
|
|
79
|
-
"@djangocfg/i18n": "^2.1.
|
|
80
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
81
|
-
"@djangocfg/ui-core": "^2.1.
|
|
78
|
+
"@djangocfg/api": "^2.1.585",
|
|
79
|
+
"@djangocfg/i18n": "^2.1.585",
|
|
80
|
+
"@djangocfg/typescript-config": "^2.1.585",
|
|
81
|
+
"@djangocfg/ui-core": "^2.1.585",
|
|
82
82
|
"@storybook/react-vite": "^10.5.0",
|
|
83
83
|
"@types/node": "^25.9.5",
|
|
84
84
|
"@types/react": "19.2.15",
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type Ref,
|
|
9
9
|
} from "react";
|
|
10
10
|
|
|
11
|
+
import { useTouchSafeStyle } from "@djangocfg/ui-core/hooks";
|
|
11
12
|
import { FIELD_SIZING, useAutosize } from "./use-autosize";
|
|
12
13
|
import { useComposer } from "../context";
|
|
13
14
|
|
|
@@ -89,6 +90,16 @@ export function ComposerInput({
|
|
|
89
90
|
const { draft, setText, handlePaste, send, canSend } = useComposer();
|
|
90
91
|
const ref = useRef<HTMLTextAreaElement | null>(null);
|
|
91
92
|
|
|
93
|
+
/**
|
|
94
|
+
* iOS WebKit auto-zoom prevention (iOS-only targeting).
|
|
95
|
+
*
|
|
96
|
+
* Returns max(16px, 1em) for iOS devices to prevent viewport zoom on focus.
|
|
97
|
+
* Android and desktop return undefined (keep optimal font-size).
|
|
98
|
+
*
|
|
99
|
+
* @see {@link @researches/2026-10-25__ios-webkit-auto-zoom}
|
|
100
|
+
*/
|
|
101
|
+
const touchSafeFontSize = useTouchSafeStyle();
|
|
102
|
+
|
|
92
103
|
/**
|
|
93
104
|
* Fill the internal ref (autosize measures through it) and the host's, if
|
|
94
105
|
* one was passed. A callback rather than handing the host `ref` directly:
|
|
@@ -195,14 +206,23 @@ export function ComposerInput({
|
|
|
195
206
|
*
|
|
196
207
|
* Empty on browsers without support, where the effect above sizes the box
|
|
197
208
|
* instead. Never both — a written `height` would override this.
|
|
209
|
+
*
|
|
210
|
+
* iOS auto-zoom prevention: merge touchSafeFontSize if present (iOS-only).
|
|
211
|
+
* On Android/desktop, touchSafeFontSize is undefined and style remains unchanged.
|
|
198
212
|
*/
|
|
199
213
|
// `fieldSizing` is newer than the pinned csstype, so the cast is the
|
|
200
214
|
// property being real and the types being behind — not a shape being
|
|
201
215
|
// forced. Remove it once csstype carries the property.
|
|
202
216
|
style={
|
|
203
217
|
FIELD_SIZING
|
|
204
|
-
? ({
|
|
205
|
-
|
|
218
|
+
? ({
|
|
219
|
+
fieldSizing: "content",
|
|
220
|
+
maxHeight: `${maxRows}lh`,
|
|
221
|
+
...(touchSafeFontSize && { fontSize: touchSafeFontSize }),
|
|
222
|
+
} as CSSProperties)
|
|
223
|
+
: touchSafeFontSize
|
|
224
|
+
? ({ fontSize: touchSafeFontSize } as CSSProperties)
|
|
225
|
+
: undefined
|
|
206
226
|
}
|
|
207
227
|
onChange={onChange}
|
|
208
228
|
onPaste={onPaste}
|
package/src/styles/composer.css
CHANGED
|
@@ -447,3 +447,44 @@
|
|
|
447
447
|
transition: none;
|
|
448
448
|
}
|
|
449
449
|
}
|
|
450
|
+
|
|
451
|
+
/* ============================================================================
|
|
452
|
+
iOS WebKit Auto-Zoom Prevention (CSS Baseline)
|
|
453
|
+
========================================================================= */
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Prevents iOS Safari/Chrome from zooming viewport when textarea gets focus.
|
|
457
|
+
*
|
|
458
|
+
* **Problem**: iOS WebKit zooms when font-size < 16px, causing conversation
|
|
459
|
+
* to "fly away" and creating critical UX failure in chat interfaces.
|
|
460
|
+
*
|
|
461
|
+
* **Solution**: Multi-layer defense:
|
|
462
|
+
* 1. CSS baseline (works without JS) — @supports iOS detection + mobile media
|
|
463
|
+
* 2. React hook (useTouchSafeStyle) — precise iOS-only targeting via device detect
|
|
464
|
+
*
|
|
465
|
+
* **WCAG Compliance**: ✅ WCAG 2.1 AA (SC 1.4.4, 1.4.10)
|
|
466
|
+
* - No viewport restrictions (user-scalable=no would violate WCAG)
|
|
467
|
+
* - Text zoom still works via browser accessibility settings
|
|
468
|
+
* - Maintains 200% text zoom capability
|
|
469
|
+
*
|
|
470
|
+
* @see {@link @researches/2026-10-25__ios-webkit-auto-zoom} Research
|
|
471
|
+
* @see {@link @djangocfg/ui-core/hooks/device/useTouchSafeStyle} React hook
|
|
472
|
+
*/
|
|
473
|
+
|
|
474
|
+
/* iOS-specific via @supports (CSS feature detection) */
|
|
475
|
+
@supports (-webkit-touch-callout: none) {
|
|
476
|
+
.composer-box textarea,
|
|
477
|
+
.composer-box input,
|
|
478
|
+
.composer-box select {
|
|
479
|
+
font-size: max(1rem, 16px);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/* Mobile baseline (all devices, fallback for browsers without @supports) */
|
|
484
|
+
@media (max-width: 768px) {
|
|
485
|
+
.composer-box textarea,
|
|
486
|
+
.composer-box input,
|
|
487
|
+
.composer-box select {
|
|
488
|
+
font-size: max(1rem, 16px);
|
|
489
|
+
}
|
|
490
|
+
}
|