@multiplatform.one/forms 7.70.0 → 7.72.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/dist/cjs/Button/index.cjs +16 -0
- package/dist/cjs/Button/index.native.js +16 -0
- package/dist/cjs/Button/index.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/echoContext.cjs +39 -0
- package/dist/cjs/FloatingPanel/echoContext.native.js +42 -0
- package/dist/cjs/FloatingPanel/echoContext.native.js.map +1 -0
- package/dist/cjs/FloatingPanel/index.cjs +212 -80
- package/dist/cjs/FloatingPanel/index.native.js +92 -17
- package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/panelWidth.cjs +92 -0
- package/dist/cjs/FloatingPanel/panelWidth.native.js +99 -0
- package/dist/cjs/FloatingPanel/panelWidth.native.js.map +1 -0
- package/dist/cjs/FloatingPanel/pointAnchor.cjs +15 -5
- package/dist/cjs/FloatingPanel/pointAnchor.native.js +15 -5
- package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/useFloatingPanel.cjs +58 -4
- package/dist/cjs/FloatingPanel/useFloatingPanel.native.js +69 -4
- package/dist/cjs/FloatingPanel/useFloatingPanel.native.js.map +1 -1
- package/dist/cjs/InputParts/index.cjs +20 -1
- package/dist/cjs/InputParts/index.native.js +22 -2
- package/dist/cjs/InputParts/index.native.js.map +1 -1
- package/dist/cjs/Wheel/NativeWheel.native.js +1 -1
- package/dist/cjs/Wheel/NativeWheel.native.js.map +1 -1
- package/dist/cjs/Wheel/index.cjs +2 -1
- package/dist/cjs/Wheel/index.native.js +4 -1
- package/dist/cjs/Wheel/index.native.js.map +1 -1
- package/dist/cjs/Wheel/wheelShared.cjs +6 -1
- package/dist/cjs/Wheel/wheelShared.native.js +7 -1
- package/dist/cjs/Wheel/wheelShared.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/index.cjs +1 -0
- package/dist/cjs/fields/Combobox/index.native.js +1 -0
- package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.cjs +6 -30
- package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +11 -34
- package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DatetimePicker.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/catalog.cjs +2 -28
- package/dist/cjs/fields/DatePicker/catalog.native.js +2 -30
- package/dist/cjs/fields/DatePicker/catalog.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/index.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/parts.cjs +11 -20
- package/dist/cjs/fields/DatePicker/parts.native.js +13 -22
- package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/SearchInput/index.cjs +23 -1
- package/dist/cjs/fields/SearchInput/index.native.js +23 -1
- package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/index.cjs +65 -44
- package/dist/cjs/fields/Select/index.native.js +69 -47
- package/dist/cjs/fields/Select/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.cjs +3 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.native.js +3 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/catalog.cjs +4 -25
- package/dist/cjs/fields/TimePicker/catalog.native.js +7 -29
- package/dist/cjs/fields/TimePicker/catalog.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/parts.cjs +8 -21
- package/dist/cjs/fields/TimePicker/parts.native.js +8 -21
- package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/shared/floatingList.cjs +13 -4
- package/dist/cjs/shared/floatingList.native.js +15 -4
- package/dist/cjs/shared/floatingList.native.js.map +1 -1
- package/dist/esm/Button/index.mjs +17 -1
- package/dist/esm/Button/index.mjs.map +1 -1
- package/dist/esm/Button/index.native.js +17 -1
- package/dist/esm/Button/index.native.js.map +1 -1
- package/dist/esm/FloatingPanel/echoContext.mjs +11 -0
- package/dist/esm/FloatingPanel/echoContext.mjs.map +1 -0
- package/dist/esm/FloatingPanel/echoContext.native.js +11 -0
- package/dist/esm/FloatingPanel/echoContext.native.js.map +1 -0
- package/dist/esm/FloatingPanel/index.mjs +213 -83
- package/dist/esm/FloatingPanel/index.mjs.map +1 -1
- package/dist/esm/FloatingPanel/index.native.js +92 -19
- package/dist/esm/FloatingPanel/index.native.js.map +1 -1
- package/dist/esm/FloatingPanel/panelWidth.mjs +63 -0
- package/dist/esm/FloatingPanel/panelWidth.mjs.map +1 -0
- package/dist/esm/FloatingPanel/panelWidth.native.js +67 -0
- package/dist/esm/FloatingPanel/panelWidth.native.js.map +1 -0
- package/dist/esm/FloatingPanel/pointAnchor.mjs +15 -5
- package/dist/esm/FloatingPanel/pointAnchor.mjs.map +1 -1
- package/dist/esm/FloatingPanel/pointAnchor.native.js +15 -5
- package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/esm/FloatingPanel/useFloatingPanel.mjs +58 -5
- package/dist/esm/FloatingPanel/useFloatingPanel.mjs.map +1 -1
- package/dist/esm/FloatingPanel/useFloatingPanel.native.js +69 -5
- package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
- package/dist/esm/InputParts/index.mjs +21 -2
- package/dist/esm/InputParts/index.mjs.map +1 -1
- package/dist/esm/InputParts/index.native.js +23 -3
- package/dist/esm/InputParts/index.native.js.map +1 -1
- package/dist/esm/Wheel/NativeWheel.native.js +1 -1
- package/dist/esm/Wheel/NativeWheel.native.js.map +1 -1
- package/dist/esm/Wheel/index.mjs +2 -1
- package/dist/esm/Wheel/index.mjs.map +1 -1
- package/dist/esm/Wheel/index.native.js +4 -1
- package/dist/esm/Wheel/index.native.js.map +1 -1
- package/dist/esm/Wheel/wheelShared.mjs +6 -1
- package/dist/esm/Wheel/wheelShared.mjs.map +1 -1
- package/dist/esm/Wheel/wheelShared.native.js +7 -1
- package/dist/esm/Wheel/wheelShared.native.js.map +1 -1
- package/dist/esm/fields/Combobox/index.mjs +1 -0
- package/dist/esm/fields/Combobox/index.mjs.map +1 -1
- package/dist/esm/fields/Combobox/index.native.js +1 -0
- package/dist/esm/fields/Combobox/index.native.js.map +1 -1
- package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs +6 -30
- package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
- package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js +11 -34
- package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
- package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
- package/dist/esm/fields/DatePicker/catalog.mjs +2 -28
- package/dist/esm/fields/DatePicker/catalog.mjs.map +1 -1
- package/dist/esm/fields/DatePicker/catalog.native.js +2 -30
- package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
- package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
- package/dist/esm/fields/DatePicker/parts.mjs +11 -20
- package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
- package/dist/esm/fields/DatePicker/parts.native.js +13 -22
- package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/esm/fields/SearchInput/index.mjs +25 -3
- package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
- package/dist/esm/fields/SearchInput/index.native.js +25 -3
- package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
- package/dist/esm/fields/Select/index.mjs +66 -45
- package/dist/esm/fields/Select/index.mjs.map +1 -1
- package/dist/esm/fields/Select/index.native.js +70 -48
- package/dist/esm/fields/Select/index.native.js.map +1 -1
- package/dist/esm/fields/Select/shouldInlineChoices.mjs +3 -1
- package/dist/esm/fields/Select/shouldInlineChoices.mjs.map +1 -1
- package/dist/esm/fields/Select/shouldInlineChoices.native.js +3 -1
- package/dist/esm/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/esm/fields/TimePicker/catalog.mjs +4 -25
- package/dist/esm/fields/TimePicker/catalog.mjs.map +1 -1
- package/dist/esm/fields/TimePicker/catalog.native.js +7 -29
- package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
- package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
- package/dist/esm/fields/TimePicker/parts.mjs +8 -21
- package/dist/esm/fields/TimePicker/parts.mjs.map +1 -1
- package/dist/esm/fields/TimePicker/parts.native.js +8 -21
- package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/shared/floatingList.mjs +14 -5
- package/dist/esm/shared/floatingList.mjs.map +1 -1
- package/dist/esm/shared/floatingList.native.js +16 -5
- package/dist/esm/shared/floatingList.native.js.map +1 -1
- package/dist/jsx/Button/index.mjs +17 -1
- package/dist/jsx/Button/index.mjs.map +1 -1
- package/dist/jsx/Button/index.native.js +16 -0
- package/dist/jsx/Button/index.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/echoContext.mjs +11 -0
- package/dist/jsx/FloatingPanel/echoContext.mjs.map +1 -0
- package/dist/jsx/FloatingPanel/echoContext.native.js +42 -0
- package/dist/jsx/FloatingPanel/echoContext.native.js.map +1 -0
- package/dist/jsx/FloatingPanel/index.mjs +213 -83
- package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/index.native.js +92 -17
- package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/panelWidth.mjs +63 -0
- package/dist/jsx/FloatingPanel/panelWidth.mjs.map +1 -0
- package/dist/jsx/FloatingPanel/panelWidth.native.js +99 -0
- package/dist/jsx/FloatingPanel/panelWidth.native.js.map +1 -0
- package/dist/jsx/FloatingPanel/pointAnchor.mjs +15 -5
- package/dist/jsx/FloatingPanel/pointAnchor.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/pointAnchor.native.js +15 -5
- package/dist/jsx/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/useFloatingPanel.mjs +58 -5
- package/dist/jsx/FloatingPanel/useFloatingPanel.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/useFloatingPanel.native.js +69 -4
- package/dist/jsx/FloatingPanel/useFloatingPanel.native.js.map +1 -1
- package/dist/jsx/InputParts/index.mjs +21 -2
- package/dist/jsx/InputParts/index.mjs.map +1 -1
- package/dist/jsx/InputParts/index.native.js +22 -2
- package/dist/jsx/InputParts/index.native.js.map +1 -1
- package/dist/jsx/Wheel/NativeWheel.native.js +1 -1
- package/dist/jsx/Wheel/NativeWheel.native.js.map +1 -1
- package/dist/jsx/Wheel/index.mjs +2 -1
- package/dist/jsx/Wheel/index.mjs.map +1 -1
- package/dist/jsx/Wheel/index.native.js +4 -1
- package/dist/jsx/Wheel/index.native.js.map +1 -1
- package/dist/jsx/Wheel/wheelShared.mjs +6 -1
- package/dist/jsx/Wheel/wheelShared.mjs.map +1 -1
- package/dist/jsx/Wheel/wheelShared.native.js +7 -1
- package/dist/jsx/Wheel/wheelShared.native.js.map +1 -1
- package/dist/jsx/fields/Combobox/index.mjs +1 -0
- package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
- package/dist/jsx/fields/Combobox/index.native.js +1 -0
- package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
- package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs +6 -30
- package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
- package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js +11 -34
- package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
- package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
- package/dist/jsx/fields/DatePicker/catalog.mjs +2 -28
- package/dist/jsx/fields/DatePicker/catalog.mjs.map +1 -1
- package/dist/jsx/fields/DatePicker/catalog.native.js +2 -30
- package/dist/jsx/fields/DatePicker/catalog.native.js.map +1 -1
- package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
- package/dist/jsx/fields/DatePicker/parts.mjs +11 -20
- package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
- package/dist/jsx/fields/DatePicker/parts.native.js +13 -22
- package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/jsx/fields/SearchInput/index.mjs +25 -3
- package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
- package/dist/jsx/fields/SearchInput/index.native.js +23 -1
- package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
- package/dist/jsx/fields/Select/index.mjs +66 -45
- package/dist/jsx/fields/Select/index.mjs.map +1 -1
- package/dist/jsx/fields/Select/index.native.js +69 -47
- package/dist/jsx/fields/Select/index.native.js.map +1 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.mjs +3 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.mjs.map +1 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.native.js +3 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/jsx/fields/TimePicker/catalog.mjs +4 -25
- package/dist/jsx/fields/TimePicker/catalog.mjs.map +1 -1
- package/dist/jsx/fields/TimePicker/catalog.native.js +7 -29
- package/dist/jsx/fields/TimePicker/catalog.native.js.map +1 -1
- package/dist/jsx/fields/TimePicker/index.native.js.map +1 -1
- package/dist/jsx/fields/TimePicker/parts.mjs +8 -21
- package/dist/jsx/fields/TimePicker/parts.mjs.map +1 -1
- package/dist/jsx/fields/TimePicker/parts.native.js +8 -21
- package/dist/jsx/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/shared/floatingList.mjs +14 -5
- package/dist/jsx/shared/floatingList.mjs.map +1 -1
- package/dist/jsx/shared/floatingList.native.js +15 -4
- package/dist/jsx/shared/floatingList.native.js.map +1 -1
- package/package.json +8 -8
- package/src/Button/index.tsx +22 -0
- package/src/FloatingPanel/FloatingPanel.echoStretch.spec.tsx +67 -0
- package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +193 -2
- package/src/FloatingPanel/FloatingPanel.seamlessCover.spec.tsx +237 -0
- package/src/FloatingPanel/echoContext.ts +22 -0
- package/src/FloatingPanel/index.native.tsx +106 -9
- package/src/FloatingPanel/index.tsx +310 -102
- package/src/FloatingPanel/panelWidth.spec.ts +158 -0
- package/src/FloatingPanel/panelWidth.ts +122 -0
- package/src/FloatingPanel/panelWidthContract.spec.ts +10 -10
- package/src/FloatingPanel/pointAnchor.spec.ts +64 -2
- package/src/FloatingPanel/pointAnchor.ts +28 -3
- package/src/FloatingPanel/useFloatingPanel.spec.tsx +124 -4
- package/src/FloatingPanel/useFloatingPanel.ts +106 -33
- package/src/InputParts/index.tsx +30 -1
- package/src/Wheel/NativeWheel.native.tsx +1 -1
- package/src/Wheel/Wheel.spec.tsx +9 -0
- package/src/Wheel/index.tsx +12 -3
- package/src/Wheel/wheelShared.ts +6 -2
- package/src/fields/Combobox/index.tsx +1 -0
- package/src/fields/DatePicker/DatePicker.stories.tsx +3 -3
- package/src/fields/DatePicker/DatetimePicker.catalog.tsx +17 -45
- package/src/fields/DatePicker/DatetimePicker.native.tsx +3 -0
- package/src/fields/DatePicker/catalog.tsx +8 -39
- package/src/fields/DatePicker/index.native.tsx +3 -0
- package/src/fields/DatePicker/parts.tsx +13 -23
- package/src/fields/DatePicker/seamlessCover.spec.tsx +180 -0
- package/src/fields/DatePicker/touchWeb.spec.tsx +109 -167
- package/src/fields/SearchInput/SearchInput.spec.tsx +40 -0
- package/src/fields/SearchInput/index.tsx +47 -2
- package/src/fields/Select/Select.containingBlock.spec.tsx +191 -0
- package/src/fields/Select/Select.stories.tsx +43 -0
- package/src/fields/Select/index.tsx +109 -45
- package/src/fields/Select/shouldInlineChoices.spec.ts +13 -0
- package/src/fields/Select/shouldInlineChoices.ts +6 -0
- package/src/fields/TimePicker/catalog.tsx +12 -33
- package/src/fields/TimePicker/index.native.tsx +2 -0
- package/src/fields/TimePicker/parts.tsx +6 -20
- package/src/index.ts +1 -0
- package/src/shared/floatingList.tsx +21 -5
- package/types/Button/index.d.ts.map +1 -1
- package/types/FloatingPanel/echoContext.d.ts +14 -0
- package/types/FloatingPanel/echoContext.d.ts.map +1 -0
- package/types/FloatingPanel/index.d.ts +59 -0
- package/types/FloatingPanel/index.d.ts.map +1 -1
- package/types/FloatingPanel/index.native.d.ts +9 -1
- package/types/FloatingPanel/index.native.d.ts.map +1 -1
- package/types/FloatingPanel/panelWidth.d.ts +71 -0
- package/types/FloatingPanel/panelWidth.d.ts.map +1 -0
- package/types/FloatingPanel/pointAnchor.d.ts +8 -1
- package/types/FloatingPanel/pointAnchor.d.ts.map +1 -1
- package/types/FloatingPanel/useFloatingPanel.d.ts +33 -2
- package/types/FloatingPanel/useFloatingPanel.d.ts.map +1 -1
- package/types/InputParts/index.d.ts +5 -1
- package/types/InputParts/index.d.ts.map +1 -1
- package/types/Wheel/index.d.ts.map +1 -1
- package/types/Wheel/wheelShared.d.ts +2 -1
- package/types/Wheel/wheelShared.d.ts.map +1 -1
- package/types/fields/Combobox/index.d.ts.map +1 -1
- package/types/fields/DatePicker/DatetimePicker.catalog.d.ts +6 -0
- package/types/fields/DatePicker/DatetimePicker.catalog.d.ts.map +1 -1
- package/types/fields/DatePicker/DatetimePicker.native.d.ts +3 -0
- package/types/fields/DatePicker/DatetimePicker.native.d.ts.map +1 -1
- package/types/fields/DatePicker/catalog.d.ts +6 -0
- package/types/fields/DatePicker/catalog.d.ts.map +1 -1
- package/types/fields/DatePicker/index.native.d.ts +3 -0
- package/types/fields/DatePicker/index.native.d.ts.map +1 -1
- package/types/fields/DatePicker/parts.d.ts +5 -7
- package/types/fields/DatePicker/parts.d.ts.map +1 -1
- package/types/fields/Input/index.d.ts +3 -1
- package/types/fields/Input/index.d.ts.map +1 -1
- package/types/fields/SearchInput/index.d.ts +11 -0
- package/types/fields/SearchInput/index.d.ts.map +1 -1
- package/types/fields/Select/index.d.ts +8 -1
- package/types/fields/Select/index.d.ts.map +1 -1
- package/types/fields/Select/shouldInlineChoices.d.ts +5 -1
- package/types/fields/Select/shouldInlineChoices.d.ts.map +1 -1
- package/types/fields/TimePicker/catalog.d.ts +7 -1
- package/types/fields/TimePicker/catalog.d.ts.map +1 -1
- package/types/fields/TimePicker/index.native.d.ts +2 -0
- package/types/fields/TimePicker/index.native.d.ts.map +1 -1
- package/types/fields/TimePicker/parts.d.ts +1 -3
- package/types/fields/TimePicker/parts.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/shared/floatingList.d.ts +5 -1
- package/types/shared/floatingList.d.ts.map +1 -1
- package/dist/cjs/shared/touchWebPicker.cjs +0 -136
- package/dist/cjs/shared/touchWebPicker.native.js +0 -154
- package/dist/cjs/shared/touchWebPicker.native.js.map +0 -1
- package/dist/esm/shared/touchWebPicker.mjs +0 -105
- package/dist/esm/shared/touchWebPicker.mjs.map +0 -1
- package/dist/esm/shared/touchWebPicker.native.js +0 -120
- package/dist/esm/shared/touchWebPicker.native.js.map +0 -1
- package/dist/jsx/shared/touchWebPicker.mjs +0 -105
- package/dist/jsx/shared/touchWebPicker.mjs.map +0 -1
- package/dist/jsx/shared/touchWebPicker.native.js +0 -154
- package/dist/jsx/shared/touchWebPicker.native.js.map +0 -1
- package/src/shared/touchWebPicker.spec.ts +0 -98
- package/src/shared/touchWebPicker.tsx +0 -158
- package/types/shared/touchWebPicker.d.ts +0 -40
- package/types/shared/touchWebPicker.d.ts.map +0 -1
|
@@ -7,9 +7,12 @@ import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
|
7
7
|
import { act } from "@testing-library/react";
|
|
8
8
|
import { useState, type ReactNode } from "react";
|
|
9
9
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
10
|
-
import { Text, XStack, YStack } from "tamagui";
|
|
10
|
+
import { Text, XStack, YStack, getTokens, getVariableValue } from "tamagui";
|
|
11
|
+
import { Button } from "../Button";
|
|
12
|
+
import { Input as InputParts } from "../InputParts";
|
|
11
13
|
import { OverlayStackProvider } from "../shared/overlayStack";
|
|
12
14
|
import { MENU_MIN_WIDTH, type CompactFace } from "./compactFace";
|
|
15
|
+
import type { PanelWidth } from "./panelWidth";
|
|
13
16
|
import { FloatingPanel } from "./index.native";
|
|
14
17
|
import { panelViewportPadding } from "./useFloatingPanel";
|
|
15
18
|
|
|
@@ -49,13 +52,22 @@ afterEach(() => {
|
|
|
49
52
|
vi.useRealTimers();
|
|
50
53
|
});
|
|
51
54
|
|
|
52
|
-
function Menu({
|
|
55
|
+
function Menu({
|
|
56
|
+
face,
|
|
57
|
+
attach = false,
|
|
58
|
+
width,
|
|
59
|
+
}: {
|
|
60
|
+
face?: CompactFace;
|
|
61
|
+
attach?: boolean;
|
|
62
|
+
width?: PanelWidth;
|
|
63
|
+
}) {
|
|
53
64
|
const [open, setOpen] = useState(false);
|
|
54
65
|
return (
|
|
55
66
|
<FloatingPanel
|
|
56
67
|
open={open}
|
|
57
68
|
onOpenChange={setOpen}
|
|
58
69
|
compactFace={face}
|
|
70
|
+
{...(width === undefined ? null : { panelWidth: width })}
|
|
59
71
|
{...(attach ? { anchorMode: "attach" as const, triggerEcho: false } : null)}
|
|
60
72
|
triggerSizing="content"
|
|
61
73
|
contentPadding="none"
|
|
@@ -207,6 +219,134 @@ describe("FloatingPanel native menu face (FZ-7830)", () => {
|
|
|
207
219
|
});
|
|
208
220
|
});
|
|
209
221
|
|
|
222
|
+
function IconMenu() {
|
|
223
|
+
const [open, setOpen] = useState(false);
|
|
224
|
+
return (
|
|
225
|
+
<FloatingPanel
|
|
226
|
+
open={open}
|
|
227
|
+
onOpenChange={setOpen}
|
|
228
|
+
compactFace="menu"
|
|
229
|
+
anchorMode="cover-trigger"
|
|
230
|
+
triggerEcho={false}
|
|
231
|
+
coverAlign="auto"
|
|
232
|
+
triggerSizing="content"
|
|
233
|
+
contentPadding="none"
|
|
234
|
+
trigger={<Text>◐</Text>}
|
|
235
|
+
triggerA11y={{ label: "Appearance" }}
|
|
236
|
+
>
|
|
237
|
+
<Text>System</Text>
|
|
238
|
+
</FloatingPanel>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function ButtonMenu() {
|
|
243
|
+
const [open, setOpen] = useState(false);
|
|
244
|
+
return (
|
|
245
|
+
<FloatingPanel
|
|
246
|
+
open={open}
|
|
247
|
+
onOpenChange={setOpen}
|
|
248
|
+
compactFace="menu"
|
|
249
|
+
contentPadding="none"
|
|
250
|
+
trigger={<Button data-testid="pill">Status: All</Button>}
|
|
251
|
+
triggerA11y={{ label: "Filter status" }}
|
|
252
|
+
>
|
|
253
|
+
<Text>Open</Text>
|
|
254
|
+
</FloatingPanel>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function FieldMenu() {
|
|
259
|
+
const [open, setOpen] = useState(false);
|
|
260
|
+
return (
|
|
261
|
+
<FloatingPanel
|
|
262
|
+
open={open}
|
|
263
|
+
onOpenChange={setOpen}
|
|
264
|
+
compactFace="menu"
|
|
265
|
+
contentPadding="none"
|
|
266
|
+
trigger={
|
|
267
|
+
<InputParts>
|
|
268
|
+
<InputParts.Box data-testid="field-box">
|
|
269
|
+
<Text>United States</Text>
|
|
270
|
+
</InputParts.Box>
|
|
271
|
+
</InputParts>
|
|
272
|
+
}
|
|
273
|
+
triggerA11y={{ label: "Country" }}
|
|
274
|
+
>
|
|
275
|
+
<Text>Canada</Text>
|
|
276
|
+
</FloatingPanel>
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const frame = () =>
|
|
281
|
+
document.querySelector<HTMLElement>('[data-testid="floating-panel-menu-surface"]');
|
|
282
|
+
const corners = (el: Element) =>
|
|
283
|
+
Array.from(el.classList)
|
|
284
|
+
.filter((c) => /^_b[tb][lr]r-/.test(c))
|
|
285
|
+
.sort();
|
|
286
|
+
const radiusAtoms = (px: number) =>
|
|
287
|
+
[`_bblr-${px}px`, `_bbrr-${px}px`, `_btlr-${px}px`, `_btrr-${px}px`].sort();
|
|
288
|
+
|
|
289
|
+
describe("LC-112 seamless cover on native (FZ-8438)", () => {
|
|
290
|
+
it("opens an icon trigger's menu ON the button from its top trailing corner (rv_d86cc201997dffd4)", () => {
|
|
291
|
+
trigger = { x: 330, y: 60, width: 44, height: 44 };
|
|
292
|
+
const result = renderWithProviders(<IconMenu />);
|
|
293
|
+
tap(result.getByRole("button", { name: "Appearance" }));
|
|
294
|
+
const panel = menu() as HTMLElement;
|
|
295
|
+
layout(panel, MENU_MIN_WIDTH, 180);
|
|
296
|
+
expect(panel.style.top).toBe(`${trigger.y}px`);
|
|
297
|
+
expect(panel.style.left).toBe(`${trigger.x + trigger.width - MENU_MIN_WIDTH}px`);
|
|
298
|
+
expect(echo()).toBeNull();
|
|
299
|
+
expect(sheet()).toBeNull();
|
|
300
|
+
expect(corners(frame() as HTMLElement)).toEqual(radiusAtoms(22));
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("keeps the shadow on an unclipped frame and clips inside it (FZ-8414)", () => {
|
|
304
|
+
const result = renderWithProviders(<IconMenu />);
|
|
305
|
+
tap(result.getByRole("button", { name: "Appearance" }));
|
|
306
|
+
const outer = frame() as HTMLElement;
|
|
307
|
+
expect(outer.className).not.toMatch(/(?:^| )_ox-hidden|_ov-hidden|_o-hidden/);
|
|
308
|
+
expect(getComputedStyle(outer).overflow).not.toBe("hidden");
|
|
309
|
+
const inner = outer.firstElementChild as HTMLElement;
|
|
310
|
+
expect(inner.className).toMatch(/hidden/);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("echoes a field with no border or fill of its own and repeats the field's arc", () => {
|
|
314
|
+
trigger = { x: 20, y: 240, width: 300, height: 44 };
|
|
315
|
+
const result = renderWithProviders(<FieldMenu />);
|
|
316
|
+
const live = result.getByTestId("field-box");
|
|
317
|
+
const atom = corners(live).find((c) => c.startsWith("_btlr-")) as string;
|
|
318
|
+
expect(atom).toBeTruthy();
|
|
319
|
+
const token = atom.match(/^_btlr-t-radius-(.+)$/);
|
|
320
|
+
const drawn = token
|
|
321
|
+
? Number(getVariableValue((getTokens().radius as Record<string, unknown>)[`$${token[1]}`]))
|
|
322
|
+
: Number(atom.match(/^_btlr-([\d.]+)px$/)?.[1]);
|
|
323
|
+
tap(result.getByRole("button", { name: "Country" }));
|
|
324
|
+
const row = echo() as HTMLElement;
|
|
325
|
+
expect(row).not.toBeNull();
|
|
326
|
+
const box = row.querySelector('[data-testid="field-box"]') as HTMLElement;
|
|
327
|
+
expect(box.className).toMatch(/_bbc-transparent/);
|
|
328
|
+
expect(box.className).toMatch(/_bg-transparent/);
|
|
329
|
+
expect(live.className).not.toMatch(/_bbc-transparent/);
|
|
330
|
+
expect(corners(frame() as HTMLElement)).toEqual(radiusAtoms(Math.min(drawn, 22)));
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("echoes a labelled Button trigger with no border or fill of its own", () => {
|
|
334
|
+
trigger = { x: 20, y: 240, width: 140, height: 44 };
|
|
335
|
+
const result = renderWithProviders(<ButtonMenu />);
|
|
336
|
+
const live = result.getByTestId("pill");
|
|
337
|
+
tap(result.getByRole("button", { name: "Filter status" }));
|
|
338
|
+
const row = echo() as HTMLElement;
|
|
339
|
+
expect(row).not.toBeNull();
|
|
340
|
+
// The echo is the trigger's own box at the start edge, not the menu's width.
|
|
341
|
+
expect(row.style.width).toBe("140px");
|
|
342
|
+
expect(row.style.alignSelf).toBe("flex-start");
|
|
343
|
+
const pill = row.querySelector('[data-testid="pill"]') as HTMLElement;
|
|
344
|
+
expect(pill.className).toMatch(/_bbc-transparent|_btc-transparent/);
|
|
345
|
+
expect(pill.className).toMatch(/_bg-transparent/);
|
|
346
|
+
expect(live.className).not.toBe(pill.className);
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
210
350
|
/** The SHC account menu's shape: an avatar-sized trigger over rows that fill their width. */
|
|
211
351
|
function AccountMenu() {
|
|
212
352
|
const [open, setOpen] = useState(false);
|
|
@@ -263,3 +403,54 @@ describe("FloatingPanel native menu face width (FZ-8220)", () => {
|
|
|
263
403
|
expect(menu()?.style.minWidth).toBe("320px");
|
|
264
404
|
});
|
|
265
405
|
});
|
|
406
|
+
|
|
407
|
+
describe("FloatingPanel native menu face panelWidth (LC-112, FZ-8438 r3)", () => {
|
|
408
|
+
const room = 390 - 2 * panelViewportPadding;
|
|
409
|
+
const open = (width?: PanelWidth) => {
|
|
410
|
+
const result = renderWithProviders(<Menu face="menu" width={width} />);
|
|
411
|
+
tap(result.getByRole("button", { name: "Stack actions" }));
|
|
412
|
+
return menu() as HTMLElement;
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
it('"content" is the default: the 250pt pull-down floor, up to the room', () => {
|
|
416
|
+
const panel = open();
|
|
417
|
+
expect(panel.style.minWidth).toBe(`${MENU_MIN_WIDTH}px`);
|
|
418
|
+
expect(panel.style.maxWidth).toBe(`${room}px`);
|
|
419
|
+
expect(panel.style.width).toBe("");
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('"trigger" is exactly the trigger\'s width', () => {
|
|
423
|
+
const panel = open("trigger");
|
|
424
|
+
expect([panel.style.minWidth, panel.style.width, panel.style.maxWidth]).toEqual([
|
|
425
|
+
"120px",
|
|
426
|
+
"120px",
|
|
427
|
+
"120px",
|
|
428
|
+
]);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('"screen" from a trigger in the gutter spans the gutters, start edge on the trigger\'s', () => {
|
|
432
|
+
const panel = open("screen");
|
|
433
|
+
const gutters = 390 - 2 * trigger.x;
|
|
434
|
+
expect(panel.style.width).toBe(`${gutters}px`);
|
|
435
|
+
layout(panel, gutters, 180);
|
|
436
|
+
expect(panel.style.left).toBe(`${trigger.x}px`);
|
|
437
|
+
expect(panel.style.top).toBe(`${trigger.y}px`);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('"screen" from a trigger deep in the row fills the room, top edge on the trigger\'s', () => {
|
|
441
|
+
trigger = { x: 186, y: 240, width: 120, height: 44 };
|
|
442
|
+
const panel = open("screen");
|
|
443
|
+
expect(panel.style.width).toBe(`${room}px`);
|
|
444
|
+
layout(panel, room, 180);
|
|
445
|
+
expect(panel.style.left).toBe(`${panelViewportPadding}px`);
|
|
446
|
+
expect(panel.style.top).toBe(`${trigger.y}px`);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it("a number is a fixed width, capped at the room", () => {
|
|
450
|
+
expect(open(300).style.width).toBe("300px");
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it("a number wider than the room stops at the margins", () => {
|
|
454
|
+
expect(open(900).style.width).toBe(`${room}px`);
|
|
455
|
+
});
|
|
456
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LC-112 seamless cover (FZ-8438, Clay's rv_a07d4308a6c445b6 and
|
|
3
|
+
* rv_0ea65e640a0ef261 notes; rv_d86cc201997dffd4 for icon triggers). An open
|
|
4
|
+
* panel is ONE surface laid exactly over its trigger: same top edge, left
|
|
5
|
+
* edge and corner arc, the trigger's content echoed in place with no border,
|
|
6
|
+
* fill or divider of its own, drawn above the trigger.
|
|
7
|
+
*/
|
|
8
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
9
|
+
import { Preset } from "@multiplatform.one/theme";
|
|
10
|
+
import { fireEvent, waitFor, within } from "@testing-library/react";
|
|
11
|
+
import { useState } from "react";
|
|
12
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
13
|
+
import { Text } from "tamagui";
|
|
14
|
+
import { Button } from "../Button";
|
|
15
|
+
import { FloatingPanel } from "./index";
|
|
16
|
+
|
|
17
|
+
type Rect = { x: number; y: number; width: number; height: number };
|
|
18
|
+
|
|
19
|
+
function measure(trigger: Rect, panelWidth = 240) {
|
|
20
|
+
const original = HTMLElement.prototype.getBoundingClientRect;
|
|
21
|
+
const rect = {
|
|
22
|
+
...trigger,
|
|
23
|
+
top: trigger.y,
|
|
24
|
+
left: trigger.x,
|
|
25
|
+
right: trigger.x + trigger.width,
|
|
26
|
+
bottom: trigger.y + trigger.height,
|
|
27
|
+
toJSON: () => ({}),
|
|
28
|
+
};
|
|
29
|
+
vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(
|
|
30
|
+
function (this: HTMLElement) {
|
|
31
|
+
if (this.hasAttribute("data-fp-reference") || this.dataset.testid === "field") return rect;
|
|
32
|
+
return original.call(this);
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
vi.spyOn(HTMLElement.prototype, "offsetWidth", "get").mockImplementation(
|
|
36
|
+
function (this: HTMLElement) {
|
|
37
|
+
return this.hasAttribute("data-fp-panel") ? panelWidth : 0;
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
vi.spyOn(HTMLElement.prototype, "scrollHeight", "get").mockImplementation(
|
|
41
|
+
function (this: HTMLElement) {
|
|
42
|
+
return this.hasAttribute("data-fp-panel") ? 160 : 0;
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** A field the way a browser paints it: border, fill and a 10px arc. */
|
|
48
|
+
function Field({ radius }: { radius: number }) {
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
data-testid="field"
|
|
52
|
+
role="combobox"
|
|
53
|
+
aria-expanded={false}
|
|
54
|
+
tabIndex={0}
|
|
55
|
+
style={{
|
|
56
|
+
borderTopLeftRadius: `${radius}px`,
|
|
57
|
+
borderRadius: `${radius}px`,
|
|
58
|
+
border: "1px solid rgb(200, 200, 200)",
|
|
59
|
+
borderBottom: "1px solid rgb(200, 200, 200)",
|
|
60
|
+
backgroundColor: "rgb(250, 250, 250)",
|
|
61
|
+
boxShadow: "0 1px 2px rgba(0, 0, 0, 0.1)",
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
Mar 5, 2026
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function FieldPanel({ radius = 10 }: { radius?: number }) {
|
|
70
|
+
const [open, setOpen] = useState(false);
|
|
71
|
+
return (
|
|
72
|
+
<FloatingPanel
|
|
73
|
+
open={open}
|
|
74
|
+
onOpenChange={setOpen}
|
|
75
|
+
contentPadding="none"
|
|
76
|
+
trigger={<Field radius={radius} />}
|
|
77
|
+
>
|
|
78
|
+
<Text>March 2026</Text>
|
|
79
|
+
</FloatingPanel>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function IconPanel({ align = "auto" }: { align?: "start" | "auto" }) {
|
|
84
|
+
const [open, setOpen] = useState(false);
|
|
85
|
+
return (
|
|
86
|
+
<FloatingPanel
|
|
87
|
+
open={open}
|
|
88
|
+
onOpenChange={setOpen}
|
|
89
|
+
anchorMode="cover-trigger"
|
|
90
|
+
triggerEcho={false}
|
|
91
|
+
coverAlign={align}
|
|
92
|
+
widthMode="fit-content"
|
|
93
|
+
triggerSizing="content"
|
|
94
|
+
trigger={<Button aria-label="Appearance">◐</Button>}
|
|
95
|
+
>
|
|
96
|
+
<Text>System</Text>
|
|
97
|
+
</FloatingPanel>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const corners = (el: Element) =>
|
|
102
|
+
Array.from(el.classList)
|
|
103
|
+
.filter((c) => /^_b[tb][lr]r-/.test(c))
|
|
104
|
+
.sort();
|
|
105
|
+
|
|
106
|
+
const radiusAtoms = (px: number) =>
|
|
107
|
+
[`_bblr-${px}px`, `_bbrr-${px}px`, `_btlr-${px}px`, `_btrr-${px}px`].sort();
|
|
108
|
+
|
|
109
|
+
async function openField(result: ReturnType<typeof renderWithProviders>) {
|
|
110
|
+
fireEvent.click(result.getByTestId("field"), { detail: 0 });
|
|
111
|
+
const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
|
|
112
|
+
return panel;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
afterEach(() => {
|
|
116
|
+
vi.restoreAllMocks();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("LC-112 seamless cover: one surface over the field (FZ-8438)", () => {
|
|
120
|
+
const field = { x: 16, y: 42, width: 400, height: 40 };
|
|
121
|
+
|
|
122
|
+
it("lays the panel's top and start edges on the field's", async () => {
|
|
123
|
+
measure(field);
|
|
124
|
+
const result = renderWithProviders(<FieldPanel />);
|
|
125
|
+
const panel = await openField(result);
|
|
126
|
+
await waitFor(() => expect(panel.style.top).toBe(`${field.y}px`));
|
|
127
|
+
expect(panel.style.left).toBe(`${field.x}px`);
|
|
128
|
+
const echo = panel.querySelector<HTMLElement>("[data-fp-trigger-row]");
|
|
129
|
+
expect(echo?.style.width).toBe(`${field.width}px`);
|
|
130
|
+
expect(echo?.style.height).toBe(`${field.height}px`);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("draws the field's own arc at all four corners", async () => {
|
|
134
|
+
measure(field);
|
|
135
|
+
const result = renderWithProviders(<FieldPanel radius={10} />);
|
|
136
|
+
const panel = await openField(result);
|
|
137
|
+
await waitFor(() => expect(corners(panel)).toEqual(radiusAtoms(10)));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("keeps the field's arc past the container cap (full preset, 20px on a 40px field)", async () => {
|
|
141
|
+
measure(field);
|
|
142
|
+
const result = renderWithProviders(
|
|
143
|
+
<Preset overrides={{ borderRadius: "full" }}>
|
|
144
|
+
<FieldPanel radius={50} />
|
|
145
|
+
</Preset>,
|
|
146
|
+
);
|
|
147
|
+
const panel = await openField(result);
|
|
148
|
+
await waitFor(() => expect(corners(panel)).toEqual(radiusAtoms(20)));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("echoes the field with no border, fill, shadow or divider of its own", async () => {
|
|
152
|
+
measure(field);
|
|
153
|
+
const result = renderWithProviders(<FieldPanel />);
|
|
154
|
+
const panel = await openField(result);
|
|
155
|
+
const frame = await waitFor(() => {
|
|
156
|
+
const found = panel.querySelector<HTMLElement>("[data-fp-echo-frame]");
|
|
157
|
+
expect(found).not.toBeNull();
|
|
158
|
+
return found as HTMLElement;
|
|
159
|
+
});
|
|
160
|
+
expect(frame.textContent).toBe("Mar 5, 2026");
|
|
161
|
+
expect(frame.style.getPropertyValue("border-color")).toBe("transparent");
|
|
162
|
+
expect(frame.style.getPropertyPriority("border-color")).toBe("important");
|
|
163
|
+
expect(frame.style.getPropertyValue("background-color")).toBe("transparent");
|
|
164
|
+
expect(frame.style.getPropertyValue("box-shadow")).toBe("none");
|
|
165
|
+
const bottom = getComputedStyle(frame).borderBottomColor;
|
|
166
|
+
expect(["transparent", "rgba(0, 0, 0, 0)"]).toContain(bottom);
|
|
167
|
+
// Layout keeps the field's widths, so the echoed text sits where it did.
|
|
168
|
+
expect(getComputedStyle(frame).borderBottomWidth).toBe("1px");
|
|
169
|
+
const row = panel.querySelector<HTMLElement>("[data-fp-trigger-row]") as HTMLElement;
|
|
170
|
+
expect(row.style.backgroundColor).toBe(getComputedStyle(panel).backgroundColor);
|
|
171
|
+
// The live field keeps its chrome; only the echo drops it.
|
|
172
|
+
expect(result.getByTestId("field").style.backgroundColor).toBe("rgb(250, 250, 250)");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("draws above the field: a fixed, stacked layer later in the document", async () => {
|
|
176
|
+
measure(field);
|
|
177
|
+
const result = renderWithProviders(<FieldPanel />);
|
|
178
|
+
const panel = await openField(result);
|
|
179
|
+
await waitFor(() => expect(panel.style.top).toBe(`${field.y}px`));
|
|
180
|
+
expect(panel.style.position).toBe("fixed");
|
|
181
|
+
expect(Number(panel.style.zIndex)).toBeGreaterThan(0);
|
|
182
|
+
const live = result.getByTestId("field");
|
|
183
|
+
expect(live.compareDocumentPosition(panel) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
184
|
+
expect(live.contains(panel)).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("LC-112 icon trigger: the menu opens on its button (rv_d86cc201997dffd4)", () => {
|
|
189
|
+
it("opens from the button's top trailing corner at the end edge, with no echo row", async () => {
|
|
190
|
+
const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
|
|
191
|
+
const button = { x: viewportWidth - 16 - 44, y: 12, width: 44, height: 44 };
|
|
192
|
+
measure(button, 200);
|
|
193
|
+
const result = renderWithProviders(<IconPanel />);
|
|
194
|
+
fireEvent.click(result.getByRole("button", { name: "Appearance" }), { detail: 0 });
|
|
195
|
+
const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
|
|
196
|
+
await waitFor(() => expect(panel.style.top).toBe(`${button.y}px`));
|
|
197
|
+
expect(panel.style.left).toBe(`${button.x + button.width - 200}px`);
|
|
198
|
+
expect(panel.style.transformOrigin).toBe("top right");
|
|
199
|
+
expect(panel.querySelector("[data-fp-trigger-row]")).toBeNull();
|
|
200
|
+
expect(result.queryByTestId("floating-panel-sheet")).toBeNull();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("opens from the button's top leading corner where that fits", async () => {
|
|
204
|
+
const button = { x: 16, y: 12, width: 44, height: 44 };
|
|
205
|
+
measure(button, 200);
|
|
206
|
+
const result = renderWithProviders(<IconPanel />);
|
|
207
|
+
fireEvent.click(result.getByRole("button", { name: "Appearance" }), { detail: 0 });
|
|
208
|
+
const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
|
|
209
|
+
await waitFor(() => expect(panel.style.top).toBe(`${button.y}px`));
|
|
210
|
+
expect(panel.style.left).toBe(`${button.x}px`);
|
|
211
|
+
expect(panel.style.transformOrigin).toBe("top left");
|
|
212
|
+
expect(within(panel).queryByRole("button", { name: "Appearance" })).toBeNull();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("slides up over its button near the bottom edge instead of opening a sheet", async () => {
|
|
216
|
+
const button = { x: 16, y: window.innerHeight - 60, width: 44, height: 44 };
|
|
217
|
+
measure(button, 200);
|
|
218
|
+
const result = renderWithProviders(<IconPanel />);
|
|
219
|
+
fireEvent.click(result.getByRole("button", { name: "Appearance" }), { detail: 0 });
|
|
220
|
+
const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
|
|
221
|
+
await waitFor(() => expect(panel.style.visibility).toBe("visible"));
|
|
222
|
+
const top = parseFloat(panel.style.top);
|
|
223
|
+
expect(top).toBeLessThan(button.y);
|
|
224
|
+
expect(top + 160).toBeGreaterThanOrEqual(button.y + button.height);
|
|
225
|
+
expect(panel.style.left).toBe(`${button.x}px`);
|
|
226
|
+
expect(result.queryByTestId("floating-panel-sheet")).toBeNull();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("never end-aligns a custom first row (triggerEcho off, coverAlign start): it collides to the sheet", async () => {
|
|
230
|
+
const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
|
|
231
|
+
const button = { x: viewportWidth - 16 - 44, y: 12, width: 44, height: 44 };
|
|
232
|
+
measure(button, 200);
|
|
233
|
+
const result = renderWithProviders(<IconPanel align="start" />);
|
|
234
|
+
fireEvent.click(result.getByRole("button", { name: "Appearance" }), { detail: 0 });
|
|
235
|
+
expect(await result.findByTestId("floating-panel-sheet")).toBeTruthy();
|
|
236
|
+
});
|
|
237
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* LC-112 seamless cover (FZ-8438): true while a field is drawn as the echo row
|
|
5
|
+
* of the panel covering it. The field keeps its geometry and drops its own
|
|
6
|
+
* border, fill and shadow, so the panel's edge and surface are the only ones.
|
|
7
|
+
*/
|
|
8
|
+
export const PanelEchoContext = createContext(false);
|
|
9
|
+
|
|
10
|
+
export function useInPanelEcho(): boolean {
|
|
11
|
+
return useContext(PanelEchoContext);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Native has no computed style to read, so a trigger's frame reports the
|
|
16
|
+
* radius it draws and a covering panel repeats it at all four corners.
|
|
17
|
+
*/
|
|
18
|
+
export const PanelTriggerRadiusContext = createContext<((radius: number) => void) | null>(null);
|
|
19
|
+
|
|
20
|
+
export function usePanelTriggerRadiusReporter(): ((radius: number) => void) | null {
|
|
21
|
+
return useContext(PanelTriggerRadiusContext);
|
|
22
|
+
}
|