@multiplatform.one/forms 7.80.0 → 7.81.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.
Files changed (221) hide show
  1. package/dist/cjs/AdaptivePopup/index.cjs +2 -1
  2. package/dist/cjs/AdaptivePopup/index.native.js +2 -1
  3. package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
  4. package/dist/cjs/Button/index.cjs +12 -5
  5. package/dist/cjs/Button/index.native.js +14 -6
  6. package/dist/cjs/Button/index.native.js.map +1 -1
  7. package/dist/cjs/FloatingPanel/PanelHeader.cjs +3 -8
  8. package/dist/cjs/FloatingPanel/PanelHeader.native.js +3 -8
  9. package/dist/cjs/FloatingPanel/PanelHeader.native.js.map +1 -1
  10. package/dist/cjs/FloatingPanel/coverRect.cjs +0 -8
  11. package/dist/cjs/FloatingPanel/coverRect.native.js +0 -8
  12. package/dist/cjs/FloatingPanel/coverRect.native.js.map +1 -1
  13. package/dist/cjs/FloatingPanel/echoContext.cjs +5 -27
  14. package/dist/cjs/FloatingPanel/echoContext.native.js +5 -28
  15. package/dist/cjs/FloatingPanel/echoContext.native.js.map +1 -1
  16. package/dist/cjs/FloatingPanel/index.cjs +49 -131
  17. package/dist/cjs/FloatingPanel/index.native.js +216 -135
  18. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  19. package/dist/cjs/fields/Combobox/index.cjs +3 -10
  20. package/dist/cjs/fields/Combobox/index.native.js +3 -10
  21. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  22. package/dist/cjs/fields/Select/InlineChoices.cjs +4 -8
  23. package/dist/cjs/fields/Select/InlineChoices.native.js +4 -8
  24. package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -1
  25. package/dist/cjs/fields/Select/index.cjs +65 -201
  26. package/dist/cjs/fields/Select/index.native.js +74 -209
  27. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  28. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.cjs +2 -2
  29. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +2 -2
  30. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  31. package/dist/cjs/index.cjs +4 -0
  32. package/dist/cjs/index.native.js +4 -0
  33. package/dist/cjs/index.native.js.map +1 -1
  34. package/dist/cjs/shared/CheckGlyph.cjs +40 -0
  35. package/dist/cjs/shared/CheckGlyph.native.js +44 -0
  36. package/dist/cjs/shared/CheckGlyph.native.js.map +1 -0
  37. package/dist/cjs/shared/checkedOnField.cjs +104 -0
  38. package/dist/cjs/shared/checkedOnField.native.js +117 -0
  39. package/dist/cjs/shared/checkedOnField.native.js.map +1 -0
  40. package/dist/cjs/shared/floatingList.cjs +12 -5
  41. package/dist/cjs/shared/floatingList.native.js +15 -7
  42. package/dist/cjs/shared/floatingList.native.js.map +1 -1
  43. package/dist/esm/AdaptivePopup/index.mjs +3 -2
  44. package/dist/esm/AdaptivePopup/index.mjs.map +1 -1
  45. package/dist/esm/AdaptivePopup/index.native.js +3 -2
  46. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  47. package/dist/esm/Button/index.mjs +12 -5
  48. package/dist/esm/Button/index.mjs.map +1 -1
  49. package/dist/esm/Button/index.native.js +14 -6
  50. package/dist/esm/Button/index.native.js.map +1 -1
  51. package/dist/esm/FloatingPanel/PanelHeader.mjs +3 -8
  52. package/dist/esm/FloatingPanel/PanelHeader.mjs.map +1 -1
  53. package/dist/esm/FloatingPanel/PanelHeader.native.js +3 -8
  54. package/dist/esm/FloatingPanel/PanelHeader.native.js.map +1 -1
  55. package/dist/esm/FloatingPanel/coverRect.mjs +1 -8
  56. package/dist/esm/FloatingPanel/coverRect.mjs.map +1 -1
  57. package/dist/esm/FloatingPanel/coverRect.native.js +1 -8
  58. package/dist/esm/FloatingPanel/coverRect.native.js.map +1 -1
  59. package/dist/esm/FloatingPanel/echoContext.mjs +4 -24
  60. package/dist/esm/FloatingPanel/echoContext.mjs.map +1 -1
  61. package/dist/esm/FloatingPanel/echoContext.native.js +4 -25
  62. package/dist/esm/FloatingPanel/echoContext.native.js.map +1 -1
  63. package/dist/esm/FloatingPanel/index.mjs +53 -135
  64. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  65. package/dist/esm/FloatingPanel/index.native.js +180 -99
  66. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  67. package/dist/esm/fields/Combobox/index.mjs +4 -11
  68. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  69. package/dist/esm/fields/Combobox/index.native.js +4 -11
  70. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  71. package/dist/esm/fields/Select/InlineChoices.mjs +2 -6
  72. package/dist/esm/fields/Select/InlineChoices.mjs.map +1 -1
  73. package/dist/esm/fields/Select/InlineChoices.native.js +2 -6
  74. package/dist/esm/fields/Select/InlineChoices.native.js.map +1 -1
  75. package/dist/esm/fields/Select/index.mjs +68 -204
  76. package/dist/esm/fields/Select/index.mjs.map +1 -1
  77. package/dist/esm/fields/Select/index.native.js +77 -212
  78. package/dist/esm/fields/Select/index.native.js.map +1 -1
  79. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +3 -3
  80. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  81. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +3 -3
  82. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  83. package/dist/esm/index.mjs +3 -1
  84. package/dist/esm/index.mjs.map +1 -1
  85. package/dist/esm/index.native.js +3 -1
  86. package/dist/esm/index.native.js.map +1 -1
  87. package/dist/esm/shared/CheckGlyph.mjs +15 -0
  88. package/dist/esm/shared/CheckGlyph.mjs.map +1 -0
  89. package/dist/esm/shared/CheckGlyph.native.js +16 -0
  90. package/dist/esm/shared/CheckGlyph.native.js.map +1 -0
  91. package/dist/esm/shared/checkedOnField.mjs +76 -0
  92. package/dist/esm/shared/checkedOnField.mjs.map +1 -0
  93. package/dist/esm/shared/checkedOnField.native.js +86 -0
  94. package/dist/esm/shared/checkedOnField.native.js.map +1 -0
  95. package/dist/esm/shared/floatingList.mjs +9 -5
  96. package/dist/esm/shared/floatingList.mjs.map +1 -1
  97. package/dist/esm/shared/floatingList.native.js +12 -7
  98. package/dist/esm/shared/floatingList.native.js.map +1 -1
  99. package/dist/jsx/AdaptivePopup/index.mjs +3 -2
  100. package/dist/jsx/AdaptivePopup/index.mjs.map +1 -1
  101. package/dist/jsx/AdaptivePopup/index.native.js +2 -1
  102. package/dist/jsx/AdaptivePopup/index.native.js.map +1 -1
  103. package/dist/jsx/Button/index.mjs +12 -5
  104. package/dist/jsx/Button/index.mjs.map +1 -1
  105. package/dist/jsx/Button/index.native.js +14 -6
  106. package/dist/jsx/Button/index.native.js.map +1 -1
  107. package/dist/jsx/FloatingPanel/PanelHeader.mjs +3 -8
  108. package/dist/jsx/FloatingPanel/PanelHeader.mjs.map +1 -1
  109. package/dist/jsx/FloatingPanel/PanelHeader.native.js +3 -8
  110. package/dist/jsx/FloatingPanel/PanelHeader.native.js.map +1 -1
  111. package/dist/jsx/FloatingPanel/coverRect.mjs +1 -8
  112. package/dist/jsx/FloatingPanel/coverRect.mjs.map +1 -1
  113. package/dist/jsx/FloatingPanel/coverRect.native.js +0 -8
  114. package/dist/jsx/FloatingPanel/coverRect.native.js.map +1 -1
  115. package/dist/jsx/FloatingPanel/echoContext.mjs +4 -24
  116. package/dist/jsx/FloatingPanel/echoContext.mjs.map +1 -1
  117. package/dist/jsx/FloatingPanel/echoContext.native.js +5 -28
  118. package/dist/jsx/FloatingPanel/echoContext.native.js.map +1 -1
  119. package/dist/jsx/FloatingPanel/index.mjs +53 -135
  120. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  121. package/dist/jsx/FloatingPanel/index.native.js +216 -135
  122. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  123. package/dist/jsx/fields/Combobox/index.mjs +4 -11
  124. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  125. package/dist/jsx/fields/Combobox/index.native.js +3 -10
  126. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  127. package/dist/jsx/fields/Select/InlineChoices.mjs +2 -6
  128. package/dist/jsx/fields/Select/InlineChoices.mjs.map +1 -1
  129. package/dist/jsx/fields/Select/InlineChoices.native.js +4 -8
  130. package/dist/jsx/fields/Select/InlineChoices.native.js.map +1 -1
  131. package/dist/jsx/fields/Select/index.mjs +68 -204
  132. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  133. package/dist/jsx/fields/Select/index.native.js +74 -209
  134. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  135. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +3 -3
  136. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  137. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +2 -2
  138. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  139. package/dist/jsx/index.js +3 -1
  140. package/dist/jsx/index.js.map +1 -1
  141. package/dist/jsx/index.mjs +3 -1
  142. package/dist/jsx/index.mjs.map +1 -1
  143. package/dist/jsx/index.native.js +4 -0
  144. package/dist/jsx/index.native.js.map +1 -1
  145. package/dist/jsx/shared/CheckGlyph.mjs +15 -0
  146. package/dist/jsx/shared/CheckGlyph.mjs.map +1 -0
  147. package/dist/jsx/shared/CheckGlyph.native.js +44 -0
  148. package/dist/jsx/shared/CheckGlyph.native.js.map +1 -0
  149. package/dist/jsx/shared/checkedOnField.mjs +76 -0
  150. package/dist/jsx/shared/checkedOnField.mjs.map +1 -0
  151. package/dist/jsx/shared/checkedOnField.native.js +117 -0
  152. package/dist/jsx/shared/checkedOnField.native.js.map +1 -0
  153. package/dist/jsx/shared/floatingList.mjs +9 -5
  154. package/dist/jsx/shared/floatingList.mjs.map +1 -1
  155. package/dist/jsx/shared/floatingList.native.js +15 -7
  156. package/dist/jsx/shared/floatingList.native.js.map +1 -1
  157. package/package.json +8 -8
  158. package/src/AdaptivePopup/index.tsx +6 -3
  159. package/src/Button/Button.iconButton.spec.tsx +39 -0
  160. package/src/Button/index.tsx +20 -8
  161. package/src/FloatingPanel/FloatingPanel.iconCover.spec.tsx +279 -0
  162. package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +78 -69
  163. package/src/FloatingPanel/FloatingPanel.seamlessCover.spec.tsx +12 -0
  164. package/src/FloatingPanel/PanelHeader.tsx +4 -12
  165. package/src/FloatingPanel/coverRect.ts +2 -15
  166. package/src/FloatingPanel/echoContext.ts +6 -40
  167. package/src/FloatingPanel/index.native.tsx +209 -144
  168. package/src/FloatingPanel/index.tsx +71 -187
  169. package/src/FloatingPanel/pointAnchor.spec.ts +1 -1
  170. package/src/FloatingPanel/pointAnchor.ts +4 -4
  171. package/src/FloatingPanel/sheetGrabber.spec.tsx +53 -0
  172. package/src/fields/Combobox/index.tsx +4 -9
  173. package/src/fields/Select/InlineChoices.tsx +2 -2
  174. package/src/fields/Select/Select.containingBlock.spec.tsx +131 -130
  175. package/src/fields/Select/Select.popUp.native.spec.tsx +276 -0
  176. package/src/fields/Select/Select.stories.tsx +26 -0
  177. package/src/fields/Select/index.tsx +84 -255
  178. package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +3 -3
  179. package/src/index.ts +2 -1
  180. package/src/shared/CheckGlyph.tsx +12 -0
  181. package/src/shared/checkedOnField.ts +116 -0
  182. package/src/shared/floatingList.spec.tsx +154 -1
  183. package/src/shared/floatingList.tsx +18 -9
  184. package/types/AdaptivePopup/index.d.ts.map +1 -1
  185. package/types/Button/index.d.ts.map +1 -1
  186. package/types/FloatingPanel/PanelHeader.d.ts +1 -6
  187. package/types/FloatingPanel/PanelHeader.d.ts.map +1 -1
  188. package/types/FloatingPanel/coverRect.d.ts +2 -11
  189. package/types/FloatingPanel/coverRect.d.ts.map +1 -1
  190. package/types/FloatingPanel/echoContext.d.ts +5 -22
  191. package/types/FloatingPanel/echoContext.d.ts.map +1 -1
  192. package/types/FloatingPanel/index.d.ts +22 -9
  193. package/types/FloatingPanel/index.d.ts.map +1 -1
  194. package/types/FloatingPanel/index.native.d.ts +8 -1
  195. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  196. package/types/FloatingPanel/pointAnchor.d.ts +4 -4
  197. package/types/fields/Combobox/index.d.ts.map +1 -1
  198. package/types/fields/Select/index.d.ts.map +1 -1
  199. package/types/index.d.ts +2 -1
  200. package/types/index.d.ts.map +1 -1
  201. package/types/shared/CheckGlyph.d.ts +10 -0
  202. package/types/shared/CheckGlyph.d.ts.map +1 -0
  203. package/types/shared/checkedOnField.d.ts +54 -0
  204. package/types/shared/checkedOnField.d.ts.map +1 -0
  205. package/types/shared/floatingList.d.ts +5 -2
  206. package/types/shared/floatingList.d.ts.map +1 -1
  207. package/dist/cjs/FloatingPanel/iconEcho.cjs +0 -106
  208. package/dist/cjs/FloatingPanel/iconEcho.native.js +0 -116
  209. package/dist/cjs/FloatingPanel/iconEcho.native.js.map +0 -1
  210. package/dist/esm/FloatingPanel/iconEcho.mjs +0 -79
  211. package/dist/esm/FloatingPanel/iconEcho.mjs.map +0 -1
  212. package/dist/esm/FloatingPanel/iconEcho.native.js +0 -86
  213. package/dist/esm/FloatingPanel/iconEcho.native.js.map +0 -1
  214. package/dist/jsx/FloatingPanel/iconEcho.mjs +0 -79
  215. package/dist/jsx/FloatingPanel/iconEcho.mjs.map +0 -1
  216. package/dist/jsx/FloatingPanel/iconEcho.native.js +0 -116
  217. package/dist/jsx/FloatingPanel/iconEcho.native.js.map +0 -1
  218. package/src/FloatingPanel/FloatingPanel.iconEcho.spec.tsx +0 -357
  219. package/src/FloatingPanel/iconEcho.tsx +0 -124
  220. package/types/FloatingPanel/iconEcho.d.ts +0 -29
  221. package/types/FloatingPanel/iconEcho.d.ts.map +0 -1
@@ -1,116 +0,0 @@
1
- "use strict";
2
-
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all) __defProp(target, name, {
9
- get: all[name],
10
- enumerable: true
11
- });
12
- };
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
- get: () => from[key],
17
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
- });
19
- }
20
- return to;
21
- };
22
- var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
23
- value: true
24
- }), mod);
25
- var iconEcho_exports = {};
26
- __export(iconEcho_exports, {
27
- ICON_ECHO_TEST_ID: () => ICON_ECHO_TEST_ID,
28
- iconEchoElement: () => iconEchoElement,
29
- iconEchoOverlays: () => iconEchoOverlays
30
- });
31
- module.exports = __toCommonJS(iconEcho_exports);
32
- var import_jsx_runtime = require("react/jsx-runtime");
33
- var import_react = require("@phosphor-icons/react");
34
- var import_react2 = require("react");
35
- var import_theme = require("@multiplatform.one/theme");
36
- var import_tamagui = require("tamagui");
37
- var import_circleGlyph = require("../Button/circleGlyph.native.js");
38
- var import_t = require("../shared/t.native.js");
39
- var ICON_ECHO_TEST_ID = "floating-panel-icon-echo";
40
- var DROPPED_PROPS = ["id", "onLongPress", "onKeyDown", "onContextMenu", "aria-haspopup", "aria-expanded", "aria-controls", "aria-describedby", "tooltip"];
41
- function iconEchoOverlays(kind, up) {
42
- return kind === "close" && !up;
43
- }
44
- function iconEchoElement(trigger, kind, onClose, surface) {
45
- var echo = echoOf(trigger, kind, onClose);
46
- if (echo == null || !surface) return echo;
47
- return /* @__PURE__ */(0, import_jsx_runtime.jsx)(import_theme.SurfaceContext.Provider, {
48
- ...surface,
49
- children: echo
50
- });
51
- }
52
- function echoOf(trigger, _kind, onClose) {
53
- if (! /* @__PURE__ */(0, import_react2.isValidElement)(trigger)) return null;
54
- var props = trigger.props;
55
- var label = (0, import_t.t)("Close");
56
- var dropped = Object.fromEntries(DROPPED_PROPS.map(function (name) {
57
- return [name, void 0];
58
- }));
59
- if (props.icon != null) {
60
- return /* @__PURE__ */(0, import_react2.cloneElement)(trigger, {
61
- ...dropped,
62
- ref: null,
63
- icon: import_react.XIcon,
64
- "aria-label": label,
65
- onPress: onClose,
66
- testID: ICON_ECHO_TEST_ID,
67
- "data-testid": ICON_ECHO_TEST_ID
68
- });
69
- }
70
- return /* @__PURE__ */(0, import_jsx_runtime.jsx)(CircleClose, {
71
- label,
72
- onClose
73
- });
74
- }
75
- var avatarPlate = "$selectedBackground";
76
- var circleGlyphFallbackPx = 18;
77
- function CircleClose(param) {
78
- var {
79
- label,
80
- onClose
81
- } = param;
82
- var _ref;
83
- var _theme_selectedColor, _theme_color;
84
- var theme = (0, import_tamagui.useTheme)();
85
- var [side, setSide] = (0, import_react2.useState)(0);
86
- var ink = (_ref = (_theme_selectedColor = theme.selectedColor) === null || _theme_selectedColor === void 0 ? void 0 : _theme_selectedColor.val) !== null && _ref !== void 0 ? _ref : (_theme_color = theme.color) === null || _theme_color === void 0 ? void 0 : _theme_color.val;
87
- return /* @__PURE__ */(0, import_jsx_runtime.jsx)(import_tamagui.View, {
88
- role: "button",
89
- "aria-label": label,
90
- tabIndex: 0,
91
- cursor: "pointer",
92
- width: "100%",
93
- height: "100%",
94
- borderRadius: 1e5,
95
- backgroundColor: avatarPlate,
96
- alignItems: "center",
97
- justifyContent: "center",
98
- pressStyle: {
99
- opacity: 0.6
100
- },
101
- onPress: onClose,
102
- onLayout: function onLayout(event) {
103
- return setSide(Math.min(event.nativeEvent.layout.width, event.nativeEvent.layout.height));
104
- },
105
- testID: ICON_ECHO_TEST_ID,
106
- "data-testid": ICON_ECHO_TEST_ID,
107
- children: /* @__PURE__ */(0, import_jsx_runtime.jsx)(import_react.XIcon, {
108
- size: side > 0 ? Math.round(side * import_circleGlyph.ICON_BUTTON_CIRCLE_GLYPH_RATIO) : circleGlyphFallbackPx,
109
- weight: "bold",
110
- color: ink,
111
- ...(0, import_circleGlyph.boldStroke)("bold", typeof ink === "string" ? ink : void 0),
112
- "aria-hidden": true
113
- })
114
- });
115
- }
116
- //# sourceMappingURL=iconEcho.native.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","iconEcho_exports","ICON_ECHO_TEST_ID","iconEchoElement","iconEchoOverlays","module","exports","import_jsx_runtime","require","import_react","import_react2","import_theme","import_tamagui","import_circleGlyph","import_t","DROPPED_PROPS","kind","up","trigger","onClose","surface","echo","echoOf","jsx","SurfaceContext","Provider","children","_kind","isValidElement","props","label","t","dropped","fromEntries","map","icon","cloneElement","ref","XIcon","onPress","testID","CircleClose","avatarPlate"],"sources":["../../../src/FloatingPanel/iconEcho.tsx"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -1,357 +0,0 @@
1
- /**
2
- * LC-112 icon trigger echo (FZ-8480, Clay's rv_2607879d3bdaf9bf): a panel
3
- * that covers the icon button it opened from draws that button again in its
4
- * exact spot, same size and plate, as an X (Round 37: every icon trigger,
5
- * the + and a menu's button alike). It closes the panel and reads "Close".
6
- */
7
- import { PlusIcon, XIcon } from "@phosphor-icons/react";
8
- import { renderWithProviders } from "@multiplatform.one/test-utils";
9
- import { fireEvent, render, waitFor, within } from "@testing-library/react";
10
- import { useState } from "react";
11
- import { MIN_PRESS_TARGET, Surface, useBarSurface } from "@multiplatform.one/theme";
12
- import { afterEach, describe, expect, it, vi } from "vitest";
13
- import { Text } from "tamagui";
14
- import { Button } from "../Button";
15
- import { GLYPH_BOLD_STROKE_UNITS } from "../Button/circleGlyph";
16
- import { FloatingPanel } from "./index";
17
- import { usePanelIconEchoBox } from "./echoContext";
18
- import { PanelHeader } from "./PanelHeader";
19
- import type { IconEcho } from "./iconEcho";
20
-
21
- type Rect = { x: number; y: number; width: number; height: number };
22
-
23
- function measure(trigger: Rect, panelWidth = 240, panelHeight = 160, surface?: Rect) {
24
- const original = HTMLElement.prototype.getBoundingClientRect;
25
- const rect = {
26
- ...trigger,
27
- top: trigger.y,
28
- left: trigger.x,
29
- right: trigger.x + trigger.width,
30
- bottom: trigger.y + trigger.height,
31
- toJSON: () => ({}),
32
- };
33
- vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(
34
- function (this: HTMLElement) {
35
- if (this.hasAttribute("data-fp-reference")) return rect;
36
- if (surface && this.hasAttribute("data-fp-cover-surface")) {
37
- return {
38
- ...surface,
39
- top: surface.y,
40
- left: surface.x,
41
- right: surface.x + surface.width,
42
- bottom: surface.y + surface.height,
43
- toJSON: () => ({}),
44
- };
45
- }
46
- return original.call(this);
47
- },
48
- );
49
- vi.spyOn(HTMLElement.prototype, "offsetWidth", "get").mockImplementation(
50
- function (this: HTMLElement) {
51
- return this.hasAttribute("data-fp-panel") ? panelWidth : 0;
52
- },
53
- );
54
- vi.spyOn(HTMLElement.prototype, "scrollHeight", "get").mockImplementation(
55
- function (this: HTMLElement) {
56
- return this.hasAttribute("data-fp-panel") ? panelHeight : 0;
57
- },
58
- );
59
- }
60
-
61
- function EchoBoxProbe() {
62
- const box = usePanelIconEchoBox();
63
- return box ? (
64
- <span
65
- data-testid="echo-box"
66
- data-height={box.height}
67
- data-left={box.left}
68
- data-right={box.right}
69
- />
70
- ) : null;
71
- }
72
-
73
- function AddPanel({ kind = "close", header = false }: { kind?: IconEcho; header?: boolean }) {
74
- const [open, setOpen] = useState(false);
75
- return (
76
- <FloatingPanel
77
- open={open}
78
- onOpenChange={setOpen}
79
- anchorMode="cover-trigger"
80
- compactFace="menu"
81
- triggerEcho={false}
82
- iconEcho={kind}
83
- coverAlign="auto"
84
- widthMode="fit-content"
85
- triggerSizing="content"
86
- contentPadding="none"
87
- trigger={<Button icon={PlusIcon} aria-label="Add node" />}
88
- >
89
- {header ? (
90
- <PanelHeader>
91
- <Text>Add a node</Text>
92
- <EchoBoxProbe />
93
- </PanelHeader>
94
- ) : (
95
- <Text>Add a node</Text>
96
- )}
97
- <Button>Copy</Button>
98
- </FloatingPanel>
99
- );
100
- }
101
-
102
- /** An account menu opened from a 32pt avatar (no `icon`, so its X is a circle). */
103
- function AvatarPanel() {
104
- return (
105
- <FloatingPanel
106
- open
107
- onOpenChange={() => {}}
108
- anchorMode="cover-trigger"
109
- compactFace="menu"
110
- triggerEcho={false}
111
- iconEcho="menu"
112
- coverAlign="auto"
113
- widthMode="fit-content"
114
- triggerSizing="content"
115
- contentPadding="none"
116
- trigger={
117
- <span role="button" aria-label="Account">
118
- AD
119
- </span>
120
- }
121
- >
122
- <Text>Sign out</Text>
123
- </FloatingPanel>
124
- );
125
- }
126
-
127
- const glyphPath = (node: Element | null | undefined) =>
128
- node?.querySelector("svg path")?.getAttribute("d");
129
-
130
- async function open(result: ReturnType<typeof renderWithProviders>) {
131
- fireEvent.click(result.getByRole("button", { name: "Add node" }), { detail: 0 });
132
- const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
133
- await waitFor(() => expect(panel.style.visibility).toBe("visible"));
134
- return panel;
135
- }
136
-
137
- afterEach(() => {
138
- vi.restoreAllMocks();
139
- });
140
-
141
- describe("LC-112 icon trigger echo on the web (FZ-8480)", () => {
142
- const viewportWidth = () => document.documentElement.clientWidth || window.innerWidth;
143
-
144
- it("draws the + again as an X on the button's exact box at the panel's top trailing corner", async () => {
145
- const button = { x: viewportWidth() - 16 - 44, y: 12, width: 44, height: 44 };
146
- measure(button, 240);
147
- const result = renderWithProviders(<AddPanel />);
148
- const panel = await open(result);
149
- const panelLeft = button.x + button.width - 240;
150
- expect(panel.style.top).toBe(`${button.y}px`);
151
- expect(panel.style.left).toBe(`${panelLeft}px`);
152
- const row = panel.querySelector<HTMLElement>("[data-fp-icon-echo]") as HTMLElement;
153
- expect(row.style.order).toBe("-1");
154
- expect(row.style.height).toBe(`${button.height}px`);
155
- // The X shares the content's first row, like a sheet's close button: it
156
- // takes no height of its own.
157
- expect(row.getAttribute("data-fp-icon-echo")).toBe("overlay");
158
- const borderTop = parseFloat(getComputedStyle(panel).borderTopWidth) || 0;
159
- expect(row.style.marginBottom).toBe(`${-(button.height - borderTop)}px`);
160
- const box = row.querySelector<HTMLElement>("[data-fp-icon-echo-box]") as HTMLElement;
161
- expect(box.style.width).toBe(`${button.width}px`);
162
- expect(box.style.height).toBe(`${button.height}px`);
163
- expect(box.style.marginLeft).toBe(`${button.x - panelLeft}px`);
164
- const echo = within(panel).getByRole("button", { name: "Close" });
165
- const x = render(<XIcon weight="bold" />);
166
- expect(glyphPath(echo)).toBe(glyphPath(x.container));
167
- x.unmount();
168
- expect(glyphPath(echo)).not.toBe(glyphPath(result.getByRole("button", { name: "Add node" })));
169
- expect(panel.querySelector("[data-fp-trigger-row]")).toBeNull();
170
- });
171
-
172
- it("renders the echo on the trigger's bar surface, so it keeps the bar button's plate", async () => {
173
- measure({ x: 16, y: 12, width: 44, height: 44 });
174
- function BarProbe({ icon: _icon, ...rest }: { icon?: unknown; [key: string]: unknown }) {
175
- const bar = useBarSurface();
176
- const press = rest.onPress as (() => void) | undefined;
177
- return (
178
- <button
179
- type="button"
180
- aria-label={rest["aria-label"] as string}
181
- data-bar={String(bar)}
182
- onClick={() => press?.()}
183
- />
184
- );
185
- }
186
- const result = renderWithProviders(
187
- <Surface bar>
188
- <FloatingPanel
189
- open
190
- onOpenChange={() => {}}
191
- anchorMode="cover-trigger"
192
- compactFace="menu"
193
- triggerEcho={false}
194
- iconEcho="close"
195
- coverAlign="auto"
196
- widthMode="fit-content"
197
- triggerSizing="content"
198
- trigger={<BarProbe icon={PlusIcon} aria-label="Add node" />}
199
- >
200
- <Text>Add a node</Text>
201
- </FloatingPanel>
202
- </Surface>,
203
- );
204
- const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
205
- expect(within(panel).getByRole("button", { name: "Close" }).getAttribute("data-bar")).toBe(
206
- "true",
207
- );
208
- });
209
-
210
- it("covers a grouped trigger's whole plate, only the pressed trigger showing as its X", async () => {
211
- const button = { x: viewportWidth() - 16 - 44, y: 12, width: 44, height: 44 };
212
- const plate = { x: button.x - 100, y: 12, width: 144, height: 44 };
213
- measure(button, 120, 160, plate);
214
- const result = renderWithProviders(
215
- <div data-fp-cover-surface="">
216
- <Button icon={PlusIcon} aria-label="Search" />
217
- <AddPanel kind="menu" />
218
- </div>,
219
- );
220
- const panel = await open(result);
221
- // The plate is wider than the menu, so the menu takes the plate's width
222
- // and both edges.
223
- expect(panel.style.left).toBe(`${plate.x}px`);
224
- expect(panel.style.top).toBe(`${plate.y}px`);
225
- const row = panel.querySelector<HTMLElement>("[data-fp-icon-echo]") as HTMLElement;
226
- // The band covers the whole plate; the group's other buttons are covered,
227
- // not echoed.
228
- expect(row.getAttribute("data-fp-icon-echo")).toBe("band");
229
- expect(row.style.height).toBe(`${plate.height}px`);
230
- expect(row.querySelector("[data-fp-group-echo]")).toBeNull();
231
- expect(within(panel).queryByRole("button", { name: "Search" })).toBeNull();
232
- const box = row.querySelector<HTMLElement>("[data-fp-icon-echo-box]") as HTMLElement;
233
- expect(box.style.marginLeft).toBe(`${button.x - plate.x}px`);
234
- expect(within(panel).getByRole("button", { name: "Close" })).toBeTruthy();
235
- });
236
-
237
- it("closes the panel when the echo is pressed", async () => {
238
- measure({ x: 16, y: 12, width: 44, height: 44 });
239
- const result = renderWithProviders(<AddPanel />);
240
- const panel = await open(result);
241
- fireEvent.click(within(panel).getByRole("button", { name: "Close" }));
242
- await waitFor(() => expect(result.queryByTestId("floating-panel-viewport")).toBeNull());
243
- });
244
-
245
- it("turns a menu trigger into an X too, in its own band", async () => {
246
- measure({ x: 16, y: 12, width: 44, height: 44 });
247
- const result = renderWithProviders(<AddPanel kind="menu" />);
248
- const panel = await open(result);
249
- const echo = within(panel).getByRole("button", { name: "Close" });
250
- const x = render(<XIcon weight="bold" />);
251
- expect(glyphPath(echo)).toBe(glyphPath(x.container));
252
- x.unmount();
253
- // A menu's rows run the full width, so its X takes its own band.
254
- const row = panel.querySelector<HTMLElement>("[data-fp-icon-echo]") as HTMLElement;
255
- expect(row.getAttribute("data-fp-icon-echo")).toBe("band");
256
- expect(row.style.marginBottom).toBe("");
257
- });
258
-
259
- it("puts a panel header on the X's line, clear of the X", async () => {
260
- const button = { x: viewportWidth() - 16 - 44, y: 12, width: 44, height: 44 };
261
- measure(button, 240);
262
- const result = renderWithProviders(<AddPanel header />);
263
- const panel = await open(result);
264
- expect(panel.querySelector("[data-fp-panel-header]")).toBeTruthy();
265
- const box = await within(panel).findByTestId("echo-box");
266
- // The header takes the X's height, and the X sits at the end edge, so it
267
- // keeps the X's whole box clear there: from the X's start to the panel's end.
268
- const panelLeft = button.x + button.width - 240;
269
- expect(box.dataset.height).toBe(`${button.height}`);
270
- expect(box.dataset.left).toBe("0");
271
- expect(box.dataset.right).toBe(`${240 - (button.x - panelLeft)}`);
272
- });
273
-
274
- it("keeps a content-sized trigger on a centring row's line", async () => {
275
- measure({ x: 16, y: 12, width: 44, height: 44 });
276
- const centred = renderWithProviders(
277
- <div style={{ display: "flex", flexDirection: "row", alignItems: "center", height: 60 }}>
278
- <AddPanel />
279
- </div>,
280
- );
281
- const inRow = centred.container.querySelector<HTMLElement>(
282
- "[data-fp-reference]",
283
- ) as HTMLElement;
284
- await waitFor(() => expect(getComputedStyle(inRow).alignSelf).not.toBe("flex-start"));
285
- centred.unmount();
286
- const column = renderWithProviders(
287
- <div style={{ display: "flex", flexDirection: "column", alignItems: "stretch" }}>
288
- <AddPanel />
289
- </div>,
290
- );
291
- const inColumn = column.container.querySelector<HTMLElement>(
292
- "[data-fp-reference]",
293
- ) as HTMLElement;
294
- expect(getComputedStyle(inColumn).alignSelf).toBe("flex-start");
295
- });
296
-
297
- it("comes last in the document, so a keyboard open lands on the content first", async () => {
298
- measure({ x: 16, y: 12, width: 44, height: 44 });
299
- const result = renderWithProviders(<AddPanel />);
300
- const panel = await open(result);
301
- const buttons = within(panel).getAllByRole("button");
302
- expect(buttons.map((b) => b.textContent || b.getAttribute("aria-label"))).toEqual([
303
- "Copy",
304
- "Close",
305
- ]);
306
- });
307
-
308
- it("opens up from the button's bottom edge near the bottom, the echo on the bottom row", async () => {
309
- const button = { x: 16, y: window.innerHeight - 60, width: 44, height: 44 };
310
- measure(button, 240, 300);
311
- const result = renderWithProviders(<AddPanel />);
312
- const panel = await open(result);
313
- const frame = getComputedStyle(panel);
314
- const borders =
315
- (parseFloat(frame.borderTopWidth) || 0) + (parseFloat(frame.borderBottomWidth) || 0);
316
- expect(parseFloat(panel.style.top) + 300 + borders).toBe(button.y + button.height);
317
- expect(panel.style.left).toBe(`${button.x}px`);
318
- const row = panel.querySelector<HTMLElement>("[data-fp-icon-echo]") as HTMLElement;
319
- expect(row.style.order).toBe("1");
320
- expect(panel.style.transformOrigin).toBe("bottom left");
321
- expect(result.queryByTestId("floating-panel-sheet")).toBeNull();
322
- });
323
-
324
- it("strokes the avatar's X to the bar buttons' bold stem (FZ-8480 follow-up)", async () => {
325
- measure({ x: 100, y: 12, width: 44, height: 44 });
326
- const bar = renderWithProviders(<AddPanel kind="menu" />);
327
- const barPanel = await open(bar);
328
- const barX = within(barPanel).getByRole("button", { name: "Close" }).querySelector("svg");
329
- expect(barX?.getAttribute("stroke-width")).toBe(String(GLYPH_BOLD_STROKE_UNITS));
330
- bar.unmount();
331
- const result = renderWithProviders(<AvatarPanel />);
332
- const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
333
- const avatarX = within(panel).getByRole("button", { name: "Close" }).querySelector("svg");
334
- expect(avatarX?.getAttribute("stroke-width")).toBe(barX?.getAttribute("stroke-width"));
335
- expect(avatarX?.getAttribute("stroke-linejoin")).toBe("round");
336
- });
337
-
338
- it("covers a 32pt avatar at its 44pt target, its centre on the row-icon column (FZ-8480 GAP)", async () => {
339
- const avatar = { x: 100, y: 18, width: 32, height: 32 };
340
- measure(avatar, 240);
341
- const result = renderWithProviders(<AvatarPanel />);
342
- const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
343
- await waitFor(() => expect(panel.style.visibility).toBe("visible"));
344
- const inset = (MIN_PRESS_TARGET - avatar.width) / 2;
345
- expect(panel.style.left).toBe(`${avatar.x - inset}px`);
346
- expect(panel.style.top).toBe(`${avatar.y - inset}px`);
347
- const row = panel.querySelector<HTMLElement>("[data-fp-icon-echo]") as HTMLElement;
348
- expect(row.style.height).toBe(`${MIN_PRESS_TARGET}px`);
349
- const box = row.querySelector<HTMLElement>("[data-fp-icon-echo-box]") as HTMLElement;
350
- expect(box.style.width).toBe(`${avatar.width}px`);
351
- expect(box.style.marginLeft).toBe(`${inset}px`);
352
- expect(box.style.marginTop).toBe(`${inset}px`);
353
- // The X's centre sits half a press target in, the centre of a menu row's
354
- // leading glyph slot.
355
- expect(inset + avatar.width / 2).toBe(MIN_PRESS_TARGET / 2);
356
- });
357
- });
@@ -1,124 +0,0 @@
1
- import { XIcon } from "@phosphor-icons/react";
2
- import { cloneElement, isValidElement, useState, type ReactElement, type ReactNode } from "react";
3
- import { SurfaceContext, type SurfaceIntent } from "@multiplatform.one/theme";
4
- import { useTheme, View } from "tamagui";
5
- import { boldStroke, ICON_BUTTON_CIRCLE_GLYPH_RATIO } from "../Button/circleGlyph";
6
- import { t } from "../shared/t";
7
-
8
- /**
9
- * How a panel covering an icon-only trigger shows the pressed button (LC-112,
10
- * FZ-8480 Round 37): in its exact spot, turned into an X that closes the
11
- * panel, the way iOS morphs a + into an X. `"close"` lays the X over the
12
- * content's header row (a panel's title shares the X's line); `"menu"` gives
13
- * the X its own band above the rows, which run the panel's full width.
14
- */
15
- export type IconEcho = "close" | "menu";
16
-
17
- export const ICON_ECHO_TEST_ID = "floating-panel-icon-echo";
18
-
19
- const DROPPED_PROPS = [
20
- "id",
21
- "onLongPress",
22
- "onKeyDown",
23
- "onContextMenu",
24
- "aria-haspopup",
25
- "aria-expanded",
26
- "aria-controls",
27
- "aria-describedby",
28
- "tooltip",
29
- ] as const;
30
-
31
- /**
32
- * An X sits in the panel's corner over the content's header row, the way a
33
- * sheet's close button shares the row with its title; a menu's X takes its
34
- * own band above the rows. A panel that opened upward always gives the echo
35
- * its own band.
36
- */
37
- export function iconEchoOverlays(kind: IconEcho, up: boolean): boolean {
38
- return kind === "close" && !up;
39
- }
40
-
41
- /**
42
- * The pressed trigger drawn again over its panel as an X: the same element
43
- * with the same size and plate and an X for its glyph, a fresh render that
44
- * shares none of the consumer's refs. It renders on the trigger's own
45
- * surface, so a bar button keeps its bar treatment (on iOS its own Liquid
46
- * Glass circle) inside the panel. Pressing it closes the panel, and it reads
47
- * "Close". A button (anything with an `icon`) is the control itself; any
48
- * other trigger (an avatar) becomes an X in a circle of its size.
49
- */
50
- export function iconEchoElement(
51
- trigger: ReactNode,
52
- kind: IconEcho,
53
- onClose: () => void,
54
- surface?: SurfaceIntent,
55
- ): ReactNode {
56
- const echo = echoOf(trigger, kind, onClose);
57
- if (echo == null || !surface) return echo;
58
- return <SurfaceContext.Provider {...surface}>{echo}</SurfaceContext.Provider>;
59
- }
60
-
61
- function echoOf(trigger: ReactNode, _kind: IconEcho, onClose: () => void): ReactNode {
62
- if (!isValidElement(trigger)) return null;
63
- const props = trigger.props as { icon?: unknown };
64
- const label = t("Close");
65
- const dropped = Object.fromEntries(DROPPED_PROPS.map((name) => [name, undefined]));
66
- if (props.icon != null) {
67
- return cloneElement(trigger as ReactElement<Record<string, unknown>>, {
68
- ...dropped,
69
- ref: null,
70
- icon: XIcon,
71
- "aria-label": label,
72
- onPress: onClose,
73
- testID: ICON_ECHO_TEST_ID,
74
- "data-testid": ICON_ECHO_TEST_ID,
75
- });
76
- }
77
- return <CircleClose label={label} onClose={onClose} />;
78
- }
79
-
80
- /** The plate an avatar draws by default, so its X keeps the avatar's circle. */
81
- const avatarPlate = "$selectedBackground";
82
-
83
- /** The X's glyph before the circle has measured itself. */
84
- const circleGlyphFallbackPx = 18;
85
-
86
- /**
87
- * An X in a circle the size of the trigger it replaces (an avatar), stroked
88
- * to the bar buttons' bold stem (LC-176), so every X in a bar reads at one
89
- * weight.
90
- */
91
- function CircleClose({ label, onClose }: { label: string; onClose: () => void }) {
92
- const theme = useTheme();
93
- const [side, setSide] = useState(0);
94
- const ink = theme.selectedColor?.val ?? theme.color?.val;
95
- return (
96
- <View
97
- role="button"
98
- aria-label={label}
99
- tabIndex={0}
100
- cursor="pointer"
101
- width="100%"
102
- height="100%"
103
- borderRadius={100000}
104
- backgroundColor={avatarPlate}
105
- alignItems="center"
106
- justifyContent="center"
107
- pressStyle={{ opacity: 0.6 }}
108
- onPress={onClose}
109
- onLayout={(event) =>
110
- setSide(Math.min(event.nativeEvent.layout.width, event.nativeEvent.layout.height))
111
- }
112
- testID={ICON_ECHO_TEST_ID}
113
- data-testid={ICON_ECHO_TEST_ID}
114
- >
115
- <XIcon
116
- size={side > 0 ? Math.round(side * ICON_BUTTON_CIRCLE_GLYPH_RATIO) : circleGlyphFallbackPx}
117
- weight="bold"
118
- color={ink}
119
- {...boldStroke("bold", typeof ink === "string" ? ink : undefined)}
120
- aria-hidden
121
- />
122
- </View>
123
- );
124
- }
@@ -1,29 +0,0 @@
1
- import { type ReactNode } from "react";
2
- import { type SurfaceIntent } from "@multiplatform.one/theme";
3
- /**
4
- * How a panel covering an icon-only trigger shows the pressed button (LC-112,
5
- * FZ-8480 Round 37): in its exact spot, turned into an X that closes the
6
- * panel, the way iOS morphs a + into an X. `"close"` lays the X over the
7
- * content's header row (a panel's title shares the X's line); `"menu"` gives
8
- * the X its own band above the rows, which run the panel's full width.
9
- */
10
- export type IconEcho = "close" | "menu";
11
- export declare const ICON_ECHO_TEST_ID = "floating-panel-icon-echo";
12
- /**
13
- * An X sits in the panel's corner over the content's header row, the way a
14
- * sheet's close button shares the row with its title; a menu's X takes its
15
- * own band above the rows. A panel that opened upward always gives the echo
16
- * its own band.
17
- */
18
- export declare function iconEchoOverlays(kind: IconEcho, up: boolean): boolean;
19
- /**
20
- * The pressed trigger drawn again over its panel as an X: the same element
21
- * with the same size and plate and an X for its glyph, a fresh render that
22
- * shares none of the consumer's refs. It renders on the trigger's own
23
- * surface, so a bar button keeps its bar treatment (on iOS its own Liquid
24
- * Glass circle) inside the panel. Pressing it closes the panel, and it reads
25
- * "Close". A button (anything with an `icon`) is the control itself; any
26
- * other trigger (an avatar) becomes an X in a circle of its size.
27
- */
28
- export declare function iconEchoElement(trigger: ReactNode, kind: IconEcho, onClose: () => void, surface?: SurfaceIntent): ReactNode;
29
- //# sourceMappingURL=iconEcho.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"iconEcho.d.ts","sourceRoot":"","sources":["../../src/FloatingPanel/iconEcho.tsx"],"names":[],"mappings":"AACA,OAAO,EAA6D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClG,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9E;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAExC,eAAO,MAAM,iBAAiB,6BAA6B,CAAC;AAc5D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,GAAG,OAAO,CAErE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,EAClB,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,MAAM,IAAI,EACnB,OAAO,CAAC,EAAE,aAAa,GACtB,SAAS,CAIX"}