@multiplatform.one/forms 7.65.0 → 7.65.1
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/dist/cjs/AdaptivePopup/index.native.js +1 -1
- package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
- package/dist/cjs/Button/index.native.js +2 -2
- package/dist/cjs/Button/index.native.js.map +1 -1
- package/dist/cjs/Chip/index.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js +1 -1
- package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/index.native.js +3 -3
- package/dist/cjs/ContextualSaveBar/index.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
- package/dist/cjs/ControlGroup/index.native.js +1 -1
- package/dist/cjs/ControlGroup/index.native.js.map +1 -1
- package/dist/cjs/DescriptionList/index.native.js +2 -2
- package/dist/cjs/DescriptionList/index.native.js.map +1 -1
- package/dist/cjs/ErrorSummary.native.js.map +1 -1
- package/dist/cjs/FieldDisplay/editMode.native.js.map +1 -1
- package/dist/cjs/FieldDisplay/formatters.native.js.map +1 -1
- package/dist/cjs/FieldDisplay/index.native.js +1 -1
- package/dist/cjs/FieldDisplay/index.native.js.map +1 -1
- package/dist/cjs/FieldGroup.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/compactFace.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/nestedAction.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/trailingAction.native.js +1 -1
- package/dist/cjs/FloatingPanel/trailingAction.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/useFloatingPanel.native.js.map +1 -1
- package/dist/cjs/Form/index.native.js +1 -1
- package/dist/cjs/Form/index.native.js.map +1 -1
- package/dist/cjs/Form/submissionController.native.js.map +1 -1
- package/dist/cjs/Form/validateOn.native.js.map +1 -1
- package/dist/cjs/FormGrid.native.js.map +1 -1
- package/dist/cjs/FormSection.native.js.map +1 -1
- package/dist/cjs/InputParts/PasswordReveal.native.js.map +1 -1
- package/dist/cjs/InputParts/index.cjs +74 -5
- package/dist/cjs/InputParts/index.native.js +99 -5
- package/dist/cjs/InputParts/index.native.js.map +1 -1
- package/dist/cjs/Label/index.native.js.map +1 -1
- package/dist/cjs/MediaPicker/base64.native.js.map +1 -1
- package/dist/cjs/MediaPicker/payload.native.js.map +1 -1
- package/dist/cjs/MediaPicker/types.native.js.map +1 -1
- package/dist/cjs/MediaPicker/useMediaPicker.native.js.map +1 -1
- package/dist/cjs/Skeleton/index.native.js.map +1 -1
- package/dist/cjs/Spinner/SpinnerGlyph.native.js.map +1 -1
- package/dist/cjs/Spinner/spinnerSize.native.js.map +1 -1
- package/dist/cjs/Table/index.native.js.map +1 -1
- package/dist/cjs/Wheel/haptic.native.js.map +1 -1
- package/dist/cjs/Wheel/index.native.js.map +1 -1
- package/dist/cjs/Wheel/wheelShared.native.js.map +1 -1
- package/dist/cjs/actionLabel.native.js.map +1 -1
- package/dist/cjs/fieldDefaults.native.js.map +1 -1
- package/dist/cjs/fieldLayout.native.js +1 -1
- package/dist/cjs/fieldLayout.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/BarcodePreview.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/BarcodeScanner.native.js +1 -1
- package/dist/cjs/fields/Barcode/code128.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/index.native.js +2 -2
- package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/qr.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/scannerTypes.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/Checkbox.native.js +1 -1
- package/dist/cjs/fields/Checkbox/Checkbox.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxBox.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxCard.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/index.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/SystemColorField.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/index.native.js +2 -2
- package/dist/cjs/fields/ColorPicker/index.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/parts.native.js +2 -2
- package/dist/cjs/fields/ColorPicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/systemColorWell.gnome.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/authorOptions.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/index.native.js +5 -5
- package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +3 -3
- package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/MonthPicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/catalog.native.js +2 -2
- package/dist/cjs/fields/DatePicker/catalog.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/fieldValueSync.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/index.native.js +2 -2
- package/dist/cjs/fields/DatePicker/parts.native.js +2 -2
- package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/utils.native.js.map +1 -1
- package/dist/cjs/fields/Duration/durationMath.native.js.map +1 -1
- package/dist/cjs/fields/Duration/index.native.js +3 -3
- package/dist/cjs/fields/Duration/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/filePickerTypes.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/index.native.js +2 -2
- package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/geoValue.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/geocoder.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/geocoderContext.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/index.native.js +5 -5
- package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/mapMath.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/mapTypes.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/photonGeocoder.native.js.map +1 -1
- package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
- package/dist/cjs/fields/Icon/index.native.js +3 -3
- package/dist/cjs/fields/Icon/index.native.js.map +1 -1
- package/dist/cjs/fields/ImageField/index.native.js +2 -2
- package/dist/cjs/fields/ImageField/index.native.js.map +1 -1
- package/dist/cjs/fields/Input/index.native.js +3 -3
- package/dist/cjs/fields/Input/index.native.js.map +1 -1
- package/dist/cjs/fields/MentionInput/index.native.js +3 -3
- package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
- package/dist/cjs/fields/OTPInput/index.native.js +3 -3
- package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
- package/dist/cjs/fields/OTPInput/otpCellCss.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/dialCodes.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/index.native.js +3 -3
- package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/phone.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/regionNames.native.js.map +1 -1
- package/dist/cjs/fields/Progress/index.native.js +1 -1
- package/dist/cjs/fields/Progress/index.native.js.map +1 -1
- package/dist/cjs/fields/RadioGroup/index.native.js +1 -1
- package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/Rating/index.native.js +1 -1
- package/dist/cjs/fields/Rating/index.native.js.map +1 -1
- package/dist/cjs/fields/Rating/ratingMath.native.js.map +1 -1
- package/dist/cjs/fields/Rating/types.native.js.map +1 -1
- package/dist/cjs/fields/SearchInput/index.native.js +2 -2
- package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/Select/index.native.js +4 -4
- package/dist/cjs/fields/Select/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/Signature/index.native.js +2 -2
- package/dist/cjs/fields/Signature/index.native.js.map +1 -1
- package/dist/cjs/fields/Slider/index.native.js +1 -1
- package/dist/cjs/fields/Slider/index.native.js.map +1 -1
- package/dist/cjs/fields/Slider/jumpMotion.native.js.map +1 -1
- package/dist/cjs/fields/Stepper/index.native.js +2 -2
- package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
- package/dist/cjs/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
- package/dist/cjs/fields/Switch/footprint.native.js.map +1 -1
- package/dist/cjs/fields/Switch/index.native.js +2 -2
- package/dist/cjs/fields/Switch/index.native.js.map +1 -1
- package/dist/cjs/fields/TextArea/index.native.js +2 -2
- package/dist/cjs/fields/TextArea/index.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/catalog.native.js +3 -3
- package/dist/cjs/fields/TimePicker/catalog.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/index.native.js +2 -2
- package/dist/cjs/fields/TimePicker/parts.native.js +1 -1
- package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
- package/dist/cjs/fields/TimeRangeScrubber/index.native.js +2 -2
- package/dist/cjs/fields/TimeRangeScrubber/index.native.js.map +1 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js +1 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
- package/dist/cjs/fields/nativeSelect.native.js.map +1 -1
- package/dist/cjs/fields/selectedOrder.native.js.map +1 -1
- package/dist/cjs/formSpacing.native.js.map +1 -1
- package/dist/cjs/hooks/useFocusManagement.native.js.map +1 -1
- package/dist/cjs/index.native.js +45 -45
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/keyboard/KeyboardDoneBar.native.js +1 -1
- package/dist/cjs/keyboard/chain.native.js.map +1 -1
- package/dist/cjs/keyboard/index.native.js.map +1 -1
- package/dist/cjs/keyboard/types.native.js.map +1 -1
- package/dist/cjs/requiredMarking.native.js.map +1 -1
- package/dist/cjs/shared/TimeColumn.native.js +1 -1
- package/dist/cjs/shared/TimeColumn.native.js.map +1 -1
- package/dist/cjs/shared/capabilityPreflight.native.js.map +1 -1
- package/dist/cjs/shared/choiceRowPress.native.js.map +1 -1
- package/dist/cjs/shared/colorRamps.native.js.map +1 -1
- package/dist/cjs/shared/devWarn.native.js.map +1 -1
- package/dist/cjs/shared/floatingList.native.js +1 -1
- package/dist/cjs/shared/floatingList.native.js.map +1 -1
- package/dist/cjs/shared/focusManagement.native.js.map +1 -1
- package/dist/cjs/shared/groupContext.native.js.map +1 -1
- package/dist/cjs/shared/i18n.native.js.map +1 -1
- package/dist/cjs/shared/instantMotion.native.js.map +1 -1
- package/dist/cjs/shared/nativeA11y.native.js.map +1 -1
- package/dist/cjs/shared/nativeAutoFocus.native.js.map +1 -1
- package/dist/cjs/shared/overlayStack.native.js.map +1 -1
- package/dist/cjs/shared/panelPortal.native.js.map +1 -1
- package/dist/cjs/shared/pickerTriggerContract.native.js.map +1 -1
- package/dist/cjs/shared/pressSlopProps.native.js.map +1 -1
- package/dist/cjs/shared/restoreRetries.native.js.map +1 -1
- package/dist/cjs/shared/t.native.js.map +1 -1
- package/dist/cjs/shared/tableCellContext.native.js.map +1 -1
- package/dist/cjs/shared/touchWebPicker.native.js.map +1 -1
- package/dist/cjs/shared/useDragScroll.native.js.map +1 -1
- package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/cjs/shared/useSheetEscapeDismiss.native.js.map +1 -1
- package/dist/cjs/shared/useWheelIncrement.native.js.map +1 -1
- package/dist/cjs/shared/utils.native.js +1 -1
- package/dist/cjs/shared/utils.native.js.map +1 -1
- package/dist/cjs/shared/zIndex.native.js.map +1 -1
- package/dist/cjs/themedPrimitives.native.js.map +1 -1
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/cjs/utils/LinkCell.native.js.map +1 -1
- package/dist/esm/InputParts/index.mjs +75 -7
- package/dist/esm/InputParts/index.mjs.map +1 -1
- package/dist/esm/InputParts/index.native.js +100 -7
- package/dist/esm/InputParts/index.native.js.map +1 -1
- package/dist/jsx/InputParts/index.mjs +75 -7
- package/dist/jsx/InputParts/index.mjs.map +1 -1
- package/dist/jsx/InputParts/index.native.js +99 -5
- package/dist/jsx/InputParts/index.native.js.map +1 -1
- package/package.json +8 -8
- package/src/InputParts/index.tsx +114 -3
- package/src/InputParts/placeholderOverlay.native.spec.tsx +229 -0
- package/src/fields/Input/Input.stories.tsx +36 -0
- package/types/InputParts/index.d.ts +8 -0
- package/types/InputParts/index.d.ts.map +1 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
2
|
+
import { act, fireEvent } from "@testing-library/react";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import type { ColorTokens } from "tamagui";
|
|
5
|
+
import { Platform } from "react-native";
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
|
+
import { Input, areaPaintsPlaceholderOverlay } from "./index";
|
|
8
|
+
|
|
9
|
+
const env = vi.hoisted(() => ({ isWeb: false }));
|
|
10
|
+
|
|
11
|
+
vi.mock("tamagui", async (importOriginal) => {
|
|
12
|
+
const original = await importOriginal<typeof import("tamagui")>();
|
|
13
|
+
return Object.defineProperty({ ...original }, "isWeb", { get: () => env.isWeb });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const platform = Platform as { OS: string };
|
|
17
|
+
const webOS = platform.OS;
|
|
18
|
+
const overlayId = "mp-placeholder-overlay";
|
|
19
|
+
const hint = "8080=web, 8443=api, 9000=minio";
|
|
20
|
+
|
|
21
|
+
function field(container: HTMLElement): HTMLInputElement {
|
|
22
|
+
const input = container.querySelector("input");
|
|
23
|
+
if (!input) throw new Error("no input rendered");
|
|
24
|
+
return input;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function nativePlaceholderColor(container: HTMLElement): string {
|
|
28
|
+
return field(container).style.getPropertyValue("--t_placeholderColor").trim();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Controlled({ initial = "" }: { initial?: string }) {
|
|
32
|
+
const [value, setValue] = useState(initial);
|
|
33
|
+
return (
|
|
34
|
+
<Input size="$3">
|
|
35
|
+
<Input.Area placeholder={hint} value={value} onChangeText={setValue} />
|
|
36
|
+
<button type="button" onClick={() => setValue("")}>
|
|
37
|
+
reset
|
|
38
|
+
</button>
|
|
39
|
+
</Input>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
env.isWeb = false;
|
|
45
|
+
platform.OS = "ios";
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
platform.OS = webOS;
|
|
50
|
+
env.isWeb = true;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("FZ-8144 iOS placeholder on the typed line", () => {
|
|
54
|
+
it("paints only on iOS, single-line, never on web or Android", () => {
|
|
55
|
+
expect(areaPaintsPlaceholderOverlay()).toBe(true);
|
|
56
|
+
expect(areaPaintsPlaceholderOverlay(true)).toBe(false);
|
|
57
|
+
platform.OS = "android";
|
|
58
|
+
expect(areaPaintsPlaceholderOverlay()).toBe(false);
|
|
59
|
+
platform.OS = "ios";
|
|
60
|
+
env.isWeb = true;
|
|
61
|
+
expect(areaPaintsPlaceholderOverlay()).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("an empty Area draws the overlay and keeps the native placeholder transparent for VoiceOver", () => {
|
|
65
|
+
const { container, getByTestId } = renderWithProviders(
|
|
66
|
+
<Input size="$3">
|
|
67
|
+
<Input.Area placeholder={hint} />
|
|
68
|
+
</Input>,
|
|
69
|
+
);
|
|
70
|
+
const overlay = getByTestId(overlayId);
|
|
71
|
+
expect(overlay.textContent).toBe(hint);
|
|
72
|
+
expect(nativePlaceholderColor(container)).toBe("transparent");
|
|
73
|
+
expect(field(container).getAttribute("placeholder")).toBe(hint);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("the overlay is hidden from accessibility and takes no touches", () => {
|
|
77
|
+
const { getByTestId, queryByText } = renderWithProviders(
|
|
78
|
+
<Input size="$3">
|
|
79
|
+
<Input.Area placeholder={hint} />
|
|
80
|
+
</Input>,
|
|
81
|
+
);
|
|
82
|
+
const overlay = getByTestId(overlayId);
|
|
83
|
+
expect(overlay.getAttribute("aria-hidden")).toBe("true");
|
|
84
|
+
expect(getComputedStyle(overlay).pointerEvents).toBe("none");
|
|
85
|
+
expect(getComputedStyle(overlay).position).toBe("absolute");
|
|
86
|
+
expect(queryByText(hint, { ignore: "[aria-hidden] *, [aria-hidden]" })).toBeNull();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("follows the consumer's placeholder colour, the native one stays transparent", () => {
|
|
90
|
+
const { container, getByTestId } = renderWithProviders(
|
|
91
|
+
<Input size="$3">
|
|
92
|
+
<Input.Area placeholder={hint} placeholderTextColor={"rgb(1, 2, 3)" as ColorTokens} />
|
|
93
|
+
</Input>,
|
|
94
|
+
);
|
|
95
|
+
expect(nativePlaceholderColor(container)).toBe("transparent");
|
|
96
|
+
const text = getByTestId(overlayId).firstElementChild as HTMLElement;
|
|
97
|
+
expect(getComputedStyle(text).color).toBe("rgb(1, 2, 3)");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("a filled Area renders no overlay", () => {
|
|
101
|
+
const { queryByTestId } = renderWithProviders(
|
|
102
|
+
<Input size="$3">
|
|
103
|
+
<Input.Area placeholder={hint} defaultValue="app.example.com" />
|
|
104
|
+
</Input>,
|
|
105
|
+
);
|
|
106
|
+
expect(queryByTestId(overlayId)).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("hides on the first typed character and returns when the field empties", () => {
|
|
110
|
+
const { container, queryByTestId } = renderWithProviders(
|
|
111
|
+
<Input size="$3">
|
|
112
|
+
<Input.Area placeholder={hint} />
|
|
113
|
+
</Input>,
|
|
114
|
+
);
|
|
115
|
+
expect(queryByTestId(overlayId)).not.toBeNull();
|
|
116
|
+
act(() => {
|
|
117
|
+
fireEvent.change(field(container), { target: { value: "a" } });
|
|
118
|
+
});
|
|
119
|
+
expect(queryByTestId(overlayId)).toBeNull();
|
|
120
|
+
act(() => {
|
|
121
|
+
fireEvent.change(field(container), { target: { value: "" } });
|
|
122
|
+
});
|
|
123
|
+
expect(queryByTestId(overlayId)).not.toBeNull();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("hides while an IME composes, before any character commits", () => {
|
|
127
|
+
const { container, queryByTestId } = renderWithProviders(<Controlled />);
|
|
128
|
+
act(() => {
|
|
129
|
+
fireEvent.change(field(container), { target: { value: "か" } });
|
|
130
|
+
});
|
|
131
|
+
expect(queryByTestId(overlayId)).toBeNull();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("tracks a controlled value both ways", () => {
|
|
135
|
+
const { container, getByText, queryByTestId } = renderWithProviders(
|
|
136
|
+
<Controlled initial="web" />,
|
|
137
|
+
);
|
|
138
|
+
expect(queryByTestId(overlayId)).toBeNull();
|
|
139
|
+
act(() => {
|
|
140
|
+
fireEvent.click(getByText("reset"));
|
|
141
|
+
});
|
|
142
|
+
expect(queryByTestId(overlayId)).not.toBeNull();
|
|
143
|
+
act(() => {
|
|
144
|
+
fireEvent.change(field(container), { target: { value: "x" } });
|
|
145
|
+
});
|
|
146
|
+
expect(queryByTestId(overlayId)).toBeNull();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("multiline keeps the native placeholder, which RN draws itself", () => {
|
|
150
|
+
const { container, queryByTestId } = renderWithProviders(
|
|
151
|
+
<Input size="$3">
|
|
152
|
+
<Input.Area placeholder={hint} multiline />
|
|
153
|
+
</Input>,
|
|
154
|
+
);
|
|
155
|
+
expect(queryByTestId(overlayId)).toBeNull();
|
|
156
|
+
expect(nativePlaceholderColor(container)).not.toBe("transparent");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("Android and web keep the native placeholder", () => {
|
|
160
|
+
platform.OS = "android";
|
|
161
|
+
const android = renderWithProviders(
|
|
162
|
+
<Input size="$3">
|
|
163
|
+
<Input.Area placeholder={hint} />
|
|
164
|
+
</Input>,
|
|
165
|
+
);
|
|
166
|
+
expect(android.queryByTestId(overlayId)).toBeNull();
|
|
167
|
+
expect(nativePlaceholderColor(android.container)).not.toBe("transparent");
|
|
168
|
+
android.unmount();
|
|
169
|
+
platform.OS = "ios";
|
|
170
|
+
env.isWeb = true;
|
|
171
|
+
const web = renderWithProviders(
|
|
172
|
+
<Input size="$3">
|
|
173
|
+
<Input.Area placeholder={hint} />
|
|
174
|
+
</Input>,
|
|
175
|
+
);
|
|
176
|
+
expect(web.queryByTestId(overlayId)).toBeNull();
|
|
177
|
+
expect(nativePlaceholderColor(web.container)).not.toBe("transparent");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("sits on the typed line: fills the Area, centred, in the field's own font and size", () => {
|
|
181
|
+
for (const size of ["$3", "$4"] as const) {
|
|
182
|
+
const { container, getByTestId, unmount } = renderWithProviders(
|
|
183
|
+
<Input size={size}>
|
|
184
|
+
<Input.Area placeholder={hint} />
|
|
185
|
+
</Input>,
|
|
186
|
+
);
|
|
187
|
+
const overlay = getByTestId(overlayId);
|
|
188
|
+
const box = getComputedStyle(overlay);
|
|
189
|
+
expect(box.position).toBe("absolute");
|
|
190
|
+
for (const edge of ["top", "bottom", "left", "right"] as const) {
|
|
191
|
+
expect(box[edge]).toBe("0px");
|
|
192
|
+
}
|
|
193
|
+
expect(box.justifyContent).toBe("center");
|
|
194
|
+
const typed = getComputedStyle(field(container));
|
|
195
|
+
const text = getComputedStyle(overlay.firstElementChild as HTMLElement);
|
|
196
|
+
expect(text.fontSize).not.toBe("");
|
|
197
|
+
expect(text.fontSize).toBe(typed.fontSize);
|
|
198
|
+
expect(text.fontFamily).toBe(typed.fontFamily);
|
|
199
|
+
expect(text.fontWeight).toBe(typed.fontWeight);
|
|
200
|
+
expect(text.lineHeight).toBe(typed.lineHeight);
|
|
201
|
+
unmount();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("follows the Area's inset and RTL alignment", () => {
|
|
206
|
+
const { getByTestId } = renderWithProviders(
|
|
207
|
+
<Input size="$3">
|
|
208
|
+
<Input.Area placeholder={hint} paddingHorizontal={12} textAlign="right" />
|
|
209
|
+
</Input>,
|
|
210
|
+
);
|
|
211
|
+
const overlay = getByTestId(overlayId);
|
|
212
|
+
expect(getComputedStyle(overlay).paddingLeft).toBe("12px");
|
|
213
|
+
expect(getComputedStyle(overlay).paddingRight).toBe("12px");
|
|
214
|
+
const text = getComputedStyle(overlay.firstElementChild as HTMLElement);
|
|
215
|
+
expect(text.textAlign).toBe("right");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("the overlay text truncates to one line with a tail ellipsis", () => {
|
|
219
|
+
const { getByTestId } = renderWithProviders(
|
|
220
|
+
<Input size="$3">
|
|
221
|
+
<Input.Area placeholder={hint} />
|
|
222
|
+
</Input>,
|
|
223
|
+
);
|
|
224
|
+
const text = getByTestId(overlayId).firstElementChild as HTMLElement;
|
|
225
|
+
const style = getComputedStyle(text);
|
|
226
|
+
expect(style.whiteSpace).toBe("nowrap");
|
|
227
|
+
expect(style.textOverflow).toBe("ellipsis");
|
|
228
|
+
});
|
|
229
|
+
});
|
|
@@ -7,6 +7,7 @@ import { useState } from "react";
|
|
|
7
7
|
import { Input as TamaguiInput, XStack, YStack } from "tamagui";
|
|
8
8
|
import { Button } from "../../Button";
|
|
9
9
|
import { Form } from "../../Form";
|
|
10
|
+
import { SearchInput } from "../SearchInput";
|
|
10
11
|
import { Input } from "./index";
|
|
11
12
|
import { Paragraph } from "@multiplatform.one/theme";
|
|
12
13
|
|
|
@@ -114,6 +115,41 @@ export const Sizes: Story = {
|
|
|
114
115
|
),
|
|
115
116
|
};
|
|
116
117
|
|
|
118
|
+
/** FZ-8144: each row pairs an empty field with a typed one; the placeholder sits on the typed line. */
|
|
119
|
+
export const PlaceholderOnTypedLine: Story = {
|
|
120
|
+
name: "Placeholder on the typed line",
|
|
121
|
+
render: () => (
|
|
122
|
+
<YStack gap="$3" maxWidth={400}>
|
|
123
|
+
{(["$3", "$4"] as const).map((size) => (
|
|
124
|
+
<XStack key={`input${size}`} gap="$2">
|
|
125
|
+
<YStack flex={1}>
|
|
126
|
+
<Input size={size} label={`Empty ${size}`} labelHidden placeholder="8080=web" />
|
|
127
|
+
</YStack>
|
|
128
|
+
<YStack flex={1}>
|
|
129
|
+
<Input size={size} label={`Typed ${size}`} labelHidden defaultValue="8080=web" />
|
|
130
|
+
</YStack>
|
|
131
|
+
</XStack>
|
|
132
|
+
))}
|
|
133
|
+
{(["$3", "$4"] as const).map((size) => (
|
|
134
|
+
<XStack key={`search${size}`} gap="$2">
|
|
135
|
+
<YStack flex={1}>
|
|
136
|
+
<SearchInput size={size} placeholder="8080=web" clearable={false} />
|
|
137
|
+
</YStack>
|
|
138
|
+
<YStack flex={1}>
|
|
139
|
+
<SearchInput size={size} defaultValue="8080=web" clearable={false} />
|
|
140
|
+
</YStack>
|
|
141
|
+
</XStack>
|
|
142
|
+
))}
|
|
143
|
+
<Input
|
|
144
|
+
size="$3"
|
|
145
|
+
label="Long placeholder"
|
|
146
|
+
labelHidden
|
|
147
|
+
placeholder="8080=web, 8443=api, 9000=minio, 5432=postgres, 6379=redis"
|
|
148
|
+
/>
|
|
149
|
+
</YStack>
|
|
150
|
+
),
|
|
151
|
+
};
|
|
152
|
+
|
|
117
153
|
export const ReadOnly: Story = {
|
|
118
154
|
args: {
|
|
119
155
|
label: "Account id",
|
|
@@ -111,6 +111,14 @@ export type InputModeValue = ComponentProps<typeof TInput>["inputMode"];
|
|
|
111
111
|
export declare function mapKeyboardTypeToInputMode(keyboardType?: string): MappedInputMode | undefined;
|
|
112
112
|
export declare function mapInputModeToKeyboardType(inputMode?: string): MappedKeyboardType | undefined;
|
|
113
113
|
export declare const inputSizeVariant: SizeVariantSpreadFunction<any>;
|
|
114
|
+
/**
|
|
115
|
+
* FZ-8144: an iOS update moved UIKit's own placeholder 3pt below the typed
|
|
116
|
+
* line on Clay's phone, while RN Text stayed put. On iOS a single-line Area
|
|
117
|
+
* paints its visible placeholder as Text centred like the typed line, and
|
|
118
|
+
* keeps the native one transparent so VoiceOver still reads it. Multiline
|
|
119
|
+
* stays native: RN draws that placeholder itself, not UIKit.
|
|
120
|
+
*/
|
|
121
|
+
export declare function areaPaintsPlaceholderOverlay(multiline?: boolean): boolean;
|
|
114
122
|
export interface InputActionProps {
|
|
115
123
|
/** Accessible name; the glyph is decorative. */
|
|
116
124
|
label: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/InputParts/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,cAAc,EACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,KAAK,IAAI,MAAM,EAWhB,MAAM,SAAS,CAAC;AACjB,OAAO,EAoBL,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAkClC,eAAO,MAAM,YAAY;UACjB,cAAc;eACT,MAAM;WACV,OAAO;YACN,WAAW,GAAG,MAAM;EACN,CAAC;AAmDzB,eAAO,MAAM,YAAY;uBACJ,OAAO;;EAE1B,CAAC;AAEH,wEAAwE;AACxE,eAAO,MAAM,eAAe,GAAI,QAAQ,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC;;;;CAYvE,CAAC;AAsBF,eAAO,MAAM,iBAAiB,QAgB5B,CAAC;AAIH,wBAAgB,yBAAyB,IAAI,IAAI,CAOhD;AAuBD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B1B,CAAC;AAyCX,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAMA;AAqTD,eAAO,MAAM,sBAAsB;;;;;;CAMzB,CAAC;AAEX,eAAO,MAAM,sBAAsB;;;;;CAKzB,CAAC;AAEX;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAC;AAEnG,sFAAsF;AACtF,MAAM,MAAM,kBAAkB,GAC5B,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,cAAc,CAAC,OAAO,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AAExE,wBAAgB,0BAA0B,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAG7F;AAED,wBAAgB,0BAA0B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAG7F;AAED,eAAO,MAAM,gBAAgB,EAAE,yBAAyB,CAAC,GAAG,CAS3D,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/InputParts/index.tsx"],"names":[],"mappings":"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"}
|