@lotics/ui 44.7.0 → 44.8.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.
@@ -45,6 +45,24 @@ interface TextInputFieldProps extends RNTextInputProps {
45
45
  * because the host already spent `CONTROL_TEXT_INSET` on it and two insets
46
46
  * stacked is a visible jump to the right on focus. */
47
47
  seamless?: boolean;
48
+ /**
49
+ * Frameless at rest — no ground, no visible edge — for a field that must read
50
+ * as its own value until touched: a table cell, a title in place. The edge
51
+ * arrives on hover and the ring on focus, exactly as in the framed variant.
52
+ *
53
+ * It is a PROP rather than a `style` the caller passes because of the order
54
+ * below. Hover is applied before `style`, so a caller-supplied
55
+ * `borderColor: "transparent"` landed on top of it and erased the hover edge
56
+ * on every bare field in the kit — leaving a control whose entire affordance
57
+ * was that edge with no affordance at all, and no way to discover it was a
58
+ * control short of clicking. Nothing measured wrong: the field had a real
59
+ * focus ring, a real role, correct type and spacing, and the hover rule was
60
+ * right there in the array being silently overwritten one line later.
61
+ *
62
+ * Distinct from `seamless`, which surrenders the surface to a HOST that draws
63
+ * it. Bare has no host — it draws its own frame, just not at rest.
64
+ */
65
+ variant?: "framed" | "bare";
48
66
  // DOM-only ARIA attrs not declared on React Native's TextInputProps. They
49
67
  // are forwarded verbatim to the underlying web input.
50
68
  "aria-controls"?: string;
@@ -63,6 +81,7 @@ export function TextInputField(props: TextInputFieldProps) {
63
81
  const {
64
82
  style,
65
83
  seamless,
84
+ variant = "framed",
66
85
  icon,
67
86
  clearable,
68
87
  onClear,
@@ -202,8 +221,20 @@ export function TextInputField(props: TextInputFieldProps) {
202
221
  icon && styles.withIcon,
203
222
  showClear && styles.withClear,
204
223
  showShortcut && shortcutWidth > 0 && { paddingRight: SHORTCUT_INSET + shortcutWidth },
205
- hovered && editable && { borderColor: HOVER_BORDER },
224
+ // RESTING FRAME first, so a caller's `style` can still override it.
225
+ variant === "bare" && styles.bare,
206
226
  style,
227
+ // ...and HOVER after `style`, which is the grammar's rule for fields
228
+ // (composition.md § the surface table) and was inverted here. A caller
229
+ // passing a resting `borderColor` — which is exactly how `bare` used
230
+ // to be expressed — silently erased the hover edge one line after it
231
+ // was computed. Order is the whole bug: every property was correct.
232
+ //
233
+ // Still BEFORE the last two. The ring is a shadow, so it does not
234
+ // compete; `seamless` must outrank hover, because there the border
235
+ // belongs to the host shell and the input drawing its own would put
236
+ // two edges on one field.
237
+ hovered && editable && { borderColor: HOVER_BORDER },
207
238
  focusVisible && !seamless && { boxShadow: FOCUS_RING },
208
239
  seamless && styles.seamless,
209
240
  ]}
@@ -277,6 +308,9 @@ const styles = StyleSheet.create({
277
308
  // Safe for height because the box is `border-box`: dropping the border changes
278
309
  // the content box, never the field's 40px outer size.
279
310
  seamless: { borderColor: "transparent", borderWidth: 0, backgroundColor: "transparent", paddingHorizontal: 0 },
311
+ // Nothing at rest — but the 1px border STAYS, transparent, so the hover edge
312
+ // costs no reflow when it arrives.
313
+ bare: { borderColor: "transparent", backgroundColor: "transparent" },
280
314
  disabled: {
281
315
  color: colors.zinc["400"],
282
316
  outlineStyle: "none" as unknown as "solid",