@tinybigui/react 0.13.0 → 0.14.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/index.cjs CHANGED
@@ -2118,277 +2118,332 @@ var FAB = React.forwardRef(
2118
2118
  }
2119
2119
  );
2120
2120
  FAB.displayName = "FAB";
2121
- var textFieldContainerVariants = classVarianceAuthority.cva(
2121
+ var textFieldRootVariants = classVarianceAuthority.cva(["relative inline-flex flex-col"], {
2122
+ variants: {
2123
+ fullWidth: {
2124
+ true: "w-full",
2125
+ false: "w-auto"
2126
+ }
2127
+ },
2128
+ defaultVariants: {
2129
+ fullWidth: false
2130
+ }
2131
+ });
2132
+ var textFieldFieldVariants = classVarianceAuthority.cva(
2122
2133
  [
2123
- // Base container styles
2124
- "relative inline-flex flex-col"
2134
+ "relative flex items-center w-full min-h-14",
2135
+ // Cursor — disabled via group-data
2136
+ "group-data-[disabled]/text-field:cursor-not-allowed",
2137
+ "group-data-[disabled]/text-field:pointer-events-none"
2125
2138
  ],
2126
2139
  {
2127
2140
  variants: {
2128
- fullWidth: {
2129
- true: "w-full",
2130
- false: "w-auto"
2141
+ variant: {
2142
+ filled: [
2143
+ "rounded-t-xs bg-surface-container-highest",
2144
+ // Disabled: background fades to on-surface/4
2145
+ "group-data-[disabled]/text-field:bg-on-surface/4"
2146
+ ],
2147
+ outlined: ["rounded-xs bg-transparent"]
2131
2148
  }
2132
2149
  },
2133
2150
  defaultVariants: {
2134
- fullWidth: false
2151
+ variant: "filled"
2135
2152
  }
2136
2153
  }
2137
2154
  );
2138
- var textFieldWrapperVariants = classVarianceAuthority.cva(
2155
+ var textFieldStateLayerVariants = classVarianceAuthority.cva([
2156
+ "absolute inset-0 rounded-t-xs pointer-events-none opacity-0",
2157
+ "bg-on-surface",
2158
+ // Effects transition — no spatial overshoot on opacity
2159
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
2160
+ // Hover: 8%
2161
+ "group-data-[hovered]/text-field:opacity-8",
2162
+ // Focus: 10% (focus wins over hover via cascade order — placed after)
2163
+ "group-data-[focused]/text-field:opacity-10",
2164
+ // No state layer when disabled
2165
+ "group-data-[disabled]/text-field:hidden"
2166
+ ]);
2167
+ var textFieldActiveIndicatorVariants = classVarianceAuthority.cva([
2168
+ "absolute bottom-0 left-0 right-0 pointer-events-none",
2169
+ // Spatial transition: height is a spatial property
2170
+ "transition-[height,background-color]",
2171
+ "duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial",
2172
+ // Base
2173
+ "h-px bg-on-surface-variant",
2174
+ // Hover
2175
+ "group-data-[hovered]/text-field:bg-on-surface",
2176
+ // Focused — 2px + primary color (focused placed after hovered to win cascade)
2177
+ "group-data-[focused]/text-field:h-0.5 group-data-[focused]/text-field:bg-primary",
2178
+ // Invalid
2179
+ "group-data-[invalid]/text-field:bg-error",
2180
+ // Invalid + focused
2181
+ "group-data-[invalid]/text-field:group-data-[focused]/text-field:bg-error",
2182
+ // Disabled: hidden
2183
+ "group-data-[disabled]/text-field:hidden"
2184
+ ]);
2185
+ var textFieldOutlineVariants = classVarianceAuthority.cva([
2186
+ "absolute inset-0 rounded-xs m-0 px-2 pointer-events-none",
2187
+ "border border-outline",
2188
+ // Effects transition for color; spatial for border-width
2189
+ "transition-[border-color,border-width]",
2190
+ "duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
2191
+ // Hover
2192
+ "group-data-[hovered]/text-field:border-on-surface",
2193
+ // Focused — 2px + primary color
2194
+ "group-data-[focused]/text-field:border-2 group-data-[focused]/text-field:border-primary",
2195
+ // Invalid
2196
+ "group-data-[invalid]/text-field:border-error",
2197
+ // Invalid + focused
2198
+ "group-data-[invalid]/text-field:group-data-[focused]/text-field:border-2",
2199
+ "group-data-[invalid]/text-field:group-data-[focused]/text-field:border-error",
2200
+ // Disabled
2201
+ "group-data-[disabled]/text-field:border-on-surface/12"
2202
+ ]);
2203
+ var textFieldNotchVariants = classVarianceAuthority.cva([
2204
+ "invisible whitespace-nowrap text-body-small px-1",
2205
+ // 0 width when not floating (no gap)
2206
+ "max-w-0 overflow-hidden",
2207
+ // Full width when floating (gap opens)
2208
+ "group-data-[float]/text-field:max-w-full",
2209
+ // Spatial transition for max-width change
2210
+ "transition-[max-width] duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial"
2211
+ ]);
2212
+ var textFieldLabelVariants = classVarianceAuthority.cva(
2139
2213
  [
2140
- // Base wrapper styles
2141
- "relative inline-flex items-center w-full",
2142
- "transition-all duration-200",
2143
- "rounded-t"
2214
+ "absolute pointer-events-none origin-top-left select-none",
2215
+ "text-body-large text-on-surface-variant",
2216
+ // Spatial + effects both use standard fast — no overshoot on font/color
2217
+ "transition-[transform,font-size,color,line-height]",
2218
+ "duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial",
2219
+ // Disabled
2220
+ "group-data-[disabled]/text-field:text-on-surface/38",
2221
+ // Invalid (placed after default, before focused so focused invalid wins)
2222
+ "group-data-[invalid]/text-field:text-error",
2223
+ // Focused (singly-chained wins by cascade order)
2224
+ "group-data-[focused]/text-field:text-primary",
2225
+ // Invalid + focused — doubly-chained, wins over single-chained focused
2226
+ "group-data-[invalid]/text-field:group-data-[focused]/text-field:text-error"
2144
2227
  ],
2145
2228
  {
2146
2229
  variants: {
2147
2230
  variant: {
2148
- filled: ["bg-surface-container-highest", "border-b-2 border-on-surface-variant"],
2149
- outlined: ["bg-transparent", "border border-outline", "rounded-b"]
2150
- },
2151
- size: {
2152
- small: "min-h-10",
2153
- medium: "min-h-12",
2154
- large: "min-h-14"
2155
- },
2156
- disabled: {
2157
- true: ["cursor-not-allowed", "opacity-38"],
2158
- false: ""
2159
- },
2160
- error: {
2161
- true: "",
2162
- false: ""
2163
- },
2164
- focused: {
2165
- true: "",
2166
- false: ""
2231
+ /**
2232
+ * Filled: label rests at center (top-1/2 -translate-y-1/2).
2233
+ * When floating: moves up to top-2 (8dp) with body-small size.
2234
+ */
2235
+ filled: [
2236
+ "top-1/2 -translate-y-1/2 left-4",
2237
+ // Floated position — sits in the top 8dp zone
2238
+ "group-data-[float]/text-field:top-2 group-data-[float]/text-field:-translate-y-0",
2239
+ "group-data-[float]/text-field:text-body-small",
2240
+ // Leading-icon offset
2241
+ "group-data-[with-leading-icon]/text-field:left-[52px]"
2242
+ ],
2243
+ /**
2244
+ * Outlined: label rests at center (top-1/2 -translate-y-1/2).
2245
+ * When floating: moves up to sit on the top border (-translate-y-1/2 from top-0).
2246
+ */
2247
+ outlined: [
2248
+ "top-1/2 -translate-y-1/2 left-3",
2249
+ // bg-surface ensures label text punches through the border
2250
+ "bg-surface px-1",
2251
+ // Floated: sits on the top border
2252
+ "group-data-[float]/text-field:top-0 group-data-[float]/text-field:-translate-y-1/2",
2253
+ "group-data-[float]/text-field:text-body-small",
2254
+ // Leading-icon offset
2255
+ "group-data-[with-leading-icon]/text-field:left-[52px]"
2256
+ ]
2167
2257
  }
2168
2258
  },
2169
- compoundVariants: [
2170
- // FILLED VARIANT - Focused state
2171
- {
2172
- variant: "filled",
2173
- focused: true,
2174
- error: false,
2175
- className: "border-primary"
2176
- },
2177
- // FILLED VARIANT - Error state
2178
- {
2179
- variant: "filled",
2180
- error: true,
2181
- className: "border-error"
2182
- },
2183
- // FILLED VARIANT - Hover state (handled via group-hover in parent)
2184
- {
2185
- variant: "filled",
2186
- disabled: false,
2187
- className: "hover:bg-on-surface/[0.08]"
2188
- },
2189
- // OUTLINED VARIANT - Focused state
2190
- {
2191
- variant: "outlined",
2192
- focused: true,
2193
- error: false,
2194
- className: "border-2 border-primary"
2195
- },
2196
- // OUTLINED VARIANT - Error state
2197
- {
2198
- variant: "outlined",
2199
- error: true,
2200
- className: "border-2 border-error"
2201
- },
2202
- // OUTLINED VARIANT - Hover state
2203
- {
2204
- variant: "outlined",
2205
- disabled: false,
2206
- className: "hover:border-on-surface"
2207
- }
2208
- ],
2209
2259
  defaultVariants: {
2210
- variant: "filled",
2211
- size: "medium",
2212
- disabled: false,
2213
- error: false,
2214
- focused: false
2260
+ variant: "filled"
2215
2261
  }
2216
2262
  }
2217
2263
  );
2218
2264
  var textFieldInputVariants = classVarianceAuthority.cva(
2219
2265
  [
2220
- // Base input styles
2221
- "w-full bg-transparent outline-none",
2222
- "text-on-surface text-base",
2223
- "placeholder:text-on-surface-variant placeholder:opacity-60",
2224
- "transition-colors duration-200"
2266
+ "relative z-10 w-full bg-transparent outline-none border-none",
2267
+ "text-body-large text-on-surface",
2268
+ "placeholder:text-on-surface-variant",
2269
+ // Placeholder hidden unless field is floating (avoids overlap with label)
2270
+ "placeholder:opacity-0",
2271
+ "group-data-[float]/text-field:placeholder:opacity-100",
2272
+ // Disabled
2273
+ "group-data-[disabled]/text-field:text-on-surface/38",
2274
+ "group-data-[disabled]/text-field:cursor-not-allowed",
2275
+ // Readonly
2276
+ "group-data-[readonly]/text-field:cursor-default",
2277
+ // Effects transition for color
2278
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
2225
2279
  ],
2226
2280
  {
2227
2281
  variants: {
2228
2282
  variant: {
2229
- filled: "px-4",
2230
- outlined: "px-4"
2231
- },
2232
- size: {
2233
- small: "h-10 py-2 text-sm",
2234
- medium: "h-12 py-3 text-base",
2235
- large: "h-14 py-4 text-lg"
2236
- },
2237
- disabled: {
2238
- true: "cursor-not-allowed",
2239
- false: ""
2240
- },
2241
- hasLeadingIcon: {
2242
- true: "pl-12",
2243
- false: ""
2244
- },
2245
- hasTrailingIcon: {
2246
- true: "pr-12",
2247
- false: ""
2283
+ /**
2284
+ * Filled: top padding creates room for floating label (label rests at 8dp).
2285
+ * Horizontal padding: 16dp left / 16dp right — but yielded to prefix/suffix
2286
+ * when they are present so the affix handles the edge spacing instead.
2287
+ */
2288
+ filled: [
2289
+ "pt-6 pb-2 px-4",
2290
+ // No label present: vertically center
2291
+ "group-data-[no-label]/text-field:py-4",
2292
+ // Leading icon horizontal offset
2293
+ "group-data-[with-leading-icon]/text-field:pl-[52px]",
2294
+ // Trailing icon horizontal offset
2295
+ "group-data-[with-trailing-icon]/text-field:pr-[52px]",
2296
+ // Prefix present: prefix handles left edge — remove input's left padding
2297
+ "group-data-[with-prefix]/text-field:pl-0",
2298
+ // Leading icon + prefix together: compound wins over both singles
2299
+ "group-data-[with-leading-icon]/text-field:group-data-[with-prefix]/text-field:pl-0",
2300
+ // Suffix present: suffix handles right edge — remove input's right padding
2301
+ "group-data-[with-suffix]/text-field:pr-0",
2302
+ // Trailing icon + suffix together: compound wins over both singles
2303
+ "group-data-[with-trailing-icon]/text-field:group-data-[with-suffix]/text-field:pr-0"
2304
+ ],
2305
+ /**
2306
+ * Outlined: label sits on the border, no extra top padding needed.
2307
+ * Horizontal padding: 16dp — yielded to prefix/suffix when present.
2308
+ */
2309
+ outlined: [
2310
+ "py-4 px-4",
2311
+ // Leading icon horizontal offset
2312
+ "group-data-[with-leading-icon]/text-field:pl-[52px]",
2313
+ // Trailing icon horizontal offset
2314
+ "group-data-[with-trailing-icon]/text-field:pr-[52px]",
2315
+ // Prefix present: prefix handles left edge
2316
+ "group-data-[with-prefix]/text-field:pl-0",
2317
+ "group-data-[with-leading-icon]/text-field:group-data-[with-prefix]/text-field:pl-0",
2318
+ // Suffix present: suffix handles right edge
2319
+ "group-data-[with-suffix]/text-field:pr-0",
2320
+ "group-data-[with-trailing-icon]/text-field:group-data-[with-suffix]/text-field:pr-0"
2321
+ ]
2248
2322
  },
2249
2323
  multiline: {
2250
- true: "resize-y",
2251
- false: ""
2324
+ true: "resize-y min-h-[1.5rem]",
2325
+ false: "h-full"
2252
2326
  }
2253
2327
  },
2254
2328
  defaultVariants: {
2255
2329
  variant: "filled",
2256
- size: "medium",
2257
- disabled: false,
2258
- hasLeadingIcon: false,
2259
- hasTrailingIcon: false,
2260
2330
  multiline: false
2261
2331
  }
2262
2332
  }
2263
2333
  );
2264
- var textFieldLabelVariants = classVarianceAuthority.cva(
2334
+ var textFieldIconVariants = classVarianceAuthority.cva(
2265
2335
  [
2266
- // Base label styles
2267
- "absolute left-4 transition-all duration-200 pointer-events-none",
2268
- "text-on-surface-variant origin-top-left"
2336
+ "absolute z-10 flex items-center justify-center size-6 pointer-events-none",
2337
+ "text-on-surface-variant",
2338
+ // Effects transition
2339
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
2340
+ // Disabled
2341
+ "group-data-[disabled]/text-field:text-on-surface/38"
2269
2342
  ],
2270
2343
  {
2271
2344
  variants: {
2272
- variant: {
2273
- filled: "top-2.5",
2274
- outlined: "top-2.5 bg-surface px-1"
2275
- },
2276
- size: {
2277
- small: "text-sm",
2278
- medium: "text-base",
2279
- large: "text-lg"
2280
- },
2281
- floating: {
2282
- true: "-translate-y-5 scale-75",
2283
- false: "scale-100"
2284
- },
2285
- focused: {
2286
- true: "text-primary",
2287
- false: ""
2288
- },
2289
- error: {
2290
- true: "text-error",
2291
- false: ""
2292
- },
2293
- disabled: {
2294
- true: "text-on-surface/38",
2295
- false: ""
2296
- },
2297
- hasLeadingIcon: {
2298
- true: "left-12",
2299
- false: ""
2345
+ position: {
2346
+ leading: "left-3",
2347
+ trailing: [
2348
+ "right-3",
2349
+ // Trailing → error color when invalid
2350
+ "group-data-[invalid]/text-field:text-error"
2351
+ ]
2300
2352
  }
2301
2353
  },
2302
- compoundVariants: [
2303
- // Outlined variant floating label positioning
2304
- {
2305
- variant: "outlined",
2306
- floating: true,
2307
- className: "top-2.5"
2308
- }
2309
- ],
2310
2354
  defaultVariants: {
2311
- variant: "filled",
2312
- size: "medium",
2313
- floating: false,
2314
- focused: false,
2315
- error: false,
2316
- disabled: false,
2317
- hasLeadingIcon: false
2355
+ position: "leading"
2318
2356
  }
2319
2357
  }
2320
2358
  );
2321
- var textFieldIconVariants = classVarianceAuthority.cva(
2359
+ var textFieldAffixVariants = classVarianceAuthority.cva(
2322
2360
  [
2323
- // Base icon styles
2324
- "absolute flex items-center justify-center",
2325
- "text-on-surface-variant transition-colors duration-200",
2326
- "pointer-events-none"
2361
+ "relative z-10 text-body-large text-on-surface-variant select-none shrink-0",
2362
+ "opacity-0 pointer-events-none",
2363
+ // Visible once label is floated
2364
+ "group-data-[float]/text-field:opacity-100 group-data-[float]/text-field:pointer-events-auto",
2365
+ // Effects transition
2366
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
2367
+ // Disabled
2368
+ "group-data-[disabled]/text-field:text-on-surface/38"
2327
2369
  ],
2328
2370
  {
2329
2371
  variants: {
2330
- position: {
2331
- leading: "left-3",
2332
- trailing: "right-3"
2333
- },
2334
- size: {
2335
- small: "w-5 h-5",
2336
- medium: "w-6 h-6",
2337
- large: "w-7 h-7"
2372
+ variant: {
2373
+ /**
2374
+ * Filled: mirror the input's pt-6 pb-2 so the text sits in the same
2375
+ * vertical zone. When no label is present, the input uses py-4 — match
2376
+ * that too so the affix stays centred with the input text.
2377
+ */
2378
+ filled: [
2379
+ "pt-6 pb-2",
2380
+ "group-data-[no-label]/text-field:pt-4 group-data-[no-label]/text-field:pb-4"
2381
+ ],
2382
+ /**
2383
+ * Outlined: input uses py-4 and h-full; items-center on the content
2384
+ * column already centres the naturally-sized affix at the same 28px
2385
+ * midpoint as the input text. No extra vertical padding needed.
2386
+ */
2387
+ outlined: []
2338
2388
  },
2339
- disabled: {
2340
- true: "opacity-38",
2341
- false: ""
2389
+ position: {
2390
+ /**
2391
+ * Prefix: sits before the input in the flex row.
2392
+ * pl-4 aligns the left text edge to the 16dp field margin.
2393
+ * With a leading icon that shifts to 52dp to clear the icon.
2394
+ * pr-0.5 is a small gap between prefix text and the input cursor.
2395
+ */
2396
+ prefix: ["pl-4", "group-data-[with-leading-icon]/text-field:pl-[52px]", "pr-0.5"],
2397
+ /**
2398
+ * Suffix: sits after the input in the flex row.
2399
+ * pl-0.5 is a small gap between the input text and the suffix.
2400
+ * pr-4 keeps 16dp from the right field edge.
2401
+ * With a trailing icon that shifts to 52dp to avoid overlap.
2402
+ */
2403
+ suffix: ["pl-0.5", "pr-4", "group-data-[with-trailing-icon]/text-field:pr-[52px]"]
2342
2404
  }
2343
2405
  },
2344
2406
  defaultVariants: {
2345
- position: "leading",
2346
- size: "medium",
2347
- disabled: false
2407
+ variant: "filled",
2408
+ position: "prefix"
2348
2409
  }
2349
2410
  }
2350
2411
  );
2351
- var textFieldHelperTextVariants = classVarianceAuthority.cva(
2412
+ var textFieldSupportingRowVariants = classVarianceAuthority.cva([
2413
+ "flex items-start justify-between w-full gap-4 px-4 pt-1"
2414
+ ]);
2415
+ var textFieldSupportingTextVariants = classVarianceAuthority.cva(
2352
2416
  [
2353
- // Base helper text styles
2354
- "text-xs mt-1 px-4 transition-colors duration-200"
2417
+ "text-body-small",
2418
+ // Effects transition for color
2419
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
2355
2420
  ],
2356
2421
  {
2357
2422
  variants: {
2358
2423
  type: {
2359
2424
  description: "text-on-surface-variant",
2360
2425
  error: "text-error"
2361
- },
2362
- disabled: {
2363
- true: "opacity-38",
2364
- false: ""
2365
2426
  }
2366
2427
  },
2367
2428
  defaultVariants: {
2368
- type: "description",
2369
- disabled: false
2429
+ type: "description"
2370
2430
  }
2371
2431
  }
2372
2432
  );
2373
- var textFieldCharacterCountVariants = classVarianceAuthority.cva(
2433
+ var textFieldCounterVariants = classVarianceAuthority.cva(
2374
2434
  [
2375
- // Base character counter styles
2376
- "text-xs mt-1 px-4 text-right text-on-surface-variant transition-colors duration-200"
2435
+ "text-body-small shrink-0 text-right",
2436
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
2377
2437
  ],
2378
2438
  {
2379
2439
  variants: {
2380
2440
  exceeded: {
2381
2441
  true: "text-error",
2382
- false: ""
2383
- },
2384
- disabled: {
2385
- true: "opacity-38",
2386
- false: ""
2442
+ false: "text-on-surface-variant"
2387
2443
  }
2388
2444
  },
2389
2445
  defaultVariants: {
2390
- exceeded: false,
2391
- disabled: false
2446
+ exceeded: false
2392
2447
  }
2393
2448
  }
2394
2449
  );
@@ -2500,12 +2555,13 @@ TextFieldHeadless.displayName = "TextFieldHeadless";
2500
2555
  var TextField = React.forwardRef(
2501
2556
  ({
2502
2557
  variant = "filled",
2503
- size = "medium",
2504
2558
  label,
2505
2559
  description,
2506
2560
  errorMessage,
2507
2561
  leadingIcon,
2508
2562
  trailingIcon,
2563
+ prefix,
2564
+ suffix,
2509
2565
  characterCount = false,
2510
2566
  maxLength,
2511
2567
  fullWidth = false,
@@ -2525,6 +2581,7 @@ var TextField = React.forwardRef(
2525
2581
  ...props
2526
2582
  }, ref) => {
2527
2583
  const spellCheckProp = spellCheck === void 0 ? void 0 : typeof spellCheck === "string" ? spellCheck === "true" : spellCheck;
2584
+ const { isHovered, hoverProps } = reactAria.useHover({ isDisabled });
2528
2585
  const headlessProps = {
2529
2586
  ...label !== void 0 ? { label } : {},
2530
2587
  ...description !== void 0 ? { description } : {},
@@ -2551,149 +2608,131 @@ var TextField = React.forwardRef(
2551
2608
  errorMessageProps,
2552
2609
  isInvalid: fieldIsInvalid,
2553
2610
  isFocused,
2611
+ isFocusVisible,
2554
2612
  currentValue,
2555
2613
  inputRef
2556
2614
  }) => {
2557
2615
  const hasValue = currentValue.length > 0;
2558
- const shouldFloatLabel = isFocused || hasValue;
2616
+ const hasPlaceholder = !!props.placeholder;
2617
+ const hasPrefix = !!prefix;
2618
+ const hasSuffix = !!suffix;
2619
+ const shouldFloat = isFocused || hasValue || hasPlaceholder || hasPrefix;
2559
2620
  const characterLength = currentValue.length;
2560
2621
  const isCharacterLimitExceeded = maxLength ? characterLength > maxLength : false;
2561
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(textFieldContainerVariants({ fullWidth }), className), children: [
2562
- /* @__PURE__ */ jsxRuntime.jsxs(
2563
- "div",
2564
- {
2565
- className: cn(
2566
- textFieldWrapperVariants({
2567
- variant,
2568
- size,
2569
- disabled: isDisabled,
2570
- error: fieldIsInvalid,
2571
- focused: isFocused
2572
- })
2573
- ),
2574
- children: [
2622
+ const hasLeadingIcon = !!leadingIcon;
2623
+ const hasTrailingIcon = !!trailingIcon;
2624
+ const hasLabel = !!label;
2625
+ const showDescription = !!description && !fieldIsInvalid;
2626
+ const showError = fieldIsInvalid && !!errorMessage;
2627
+ const showCounter = characterCount && maxLength !== void 0;
2628
+ const showSupportingRow = showDescription || showError || showCounter;
2629
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2630
+ "div",
2631
+ {
2632
+ className: cn(textFieldRootVariants({ fullWidth }), "group/text-field", className),
2633
+ ...getInteractionDataAttributes({
2634
+ isHovered,
2635
+ isFocusVisible,
2636
+ isDisabled,
2637
+ isReadOnly,
2638
+ isInvalid: fieldIsInvalid
2639
+ }),
2640
+ "data-focused": isFocused ? "" : void 0,
2641
+ "data-float": shouldFloat ? "" : void 0,
2642
+ "data-with-leading-icon": hasLeadingIcon ? "" : void 0,
2643
+ "data-with-trailing-icon": hasTrailingIcon ? "" : void 0,
2644
+ "data-with-prefix": hasPrefix ? "" : void 0,
2645
+ "data-with-suffix": hasSuffix ? "" : void 0,
2646
+ "data-no-label": !hasLabel ? "" : void 0,
2647
+ "data-multiline": multiline ? "" : void 0,
2648
+ children: [
2649
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ...hoverProps, className: cn(textFieldFieldVariants({ variant })), children: [
2650
+ variant === "filled" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(textFieldStateLayerVariants()), "aria-hidden": "true" }),
2575
2651
  leadingIcon && /* @__PURE__ */ jsxRuntime.jsx(
2576
2652
  "span",
2577
2653
  {
2578
- className: textFieldIconVariants({
2579
- position: "leading",
2580
- size,
2581
- disabled: isDisabled
2582
- }),
2654
+ className: cn(textFieldIconVariants({ position: "leading" })),
2655
+ "aria-hidden": "true",
2583
2656
  children: leadingIcon
2584
2657
  }
2585
2658
  ),
2586
- label && /* @__PURE__ */ jsxRuntime.jsxs(
2587
- "label",
2659
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-full min-w-0 flex-1 items-center", children: [
2660
+ label && /* @__PURE__ */ jsxRuntime.jsxs("label", { ...labelProps, className: cn(textFieldLabelVariants({ variant })), children: [
2661
+ label,
2662
+ isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2009*" })
2663
+ ] }),
2664
+ prefix && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(textFieldAffixVariants({ variant, position: "prefix" })), children: prefix }),
2665
+ multiline ? /* @__PURE__ */ jsxRuntime.jsx(
2666
+ "textarea",
2667
+ {
2668
+ ...inputProps,
2669
+ ref: inputRef,
2670
+ className: cn(textFieldInputVariants({ variant, multiline: true })),
2671
+ rows,
2672
+ spellCheck: spellCheckProp
2673
+ }
2674
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2675
+ "input",
2676
+ {
2677
+ ...inputProps,
2678
+ ref: inputRef,
2679
+ className: cn(textFieldInputVariants({ variant, multiline: false })),
2680
+ spellCheck: spellCheckProp
2681
+ }
2682
+ ),
2683
+ suffix && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(textFieldAffixVariants({ variant, position: "suffix" })), children: suffix })
2684
+ ] }),
2685
+ trailingIcon && /* @__PURE__ */ jsxRuntime.jsx(
2686
+ "span",
2588
2687
  {
2589
- ...labelProps,
2590
- className: cn(
2591
- textFieldLabelVariants({
2592
- variant,
2593
- size,
2594
- floating: shouldFloatLabel,
2595
- focused: isFocused,
2596
- error: fieldIsInvalid,
2597
- disabled: isDisabled,
2598
- hasLeadingIcon: !!leadingIcon
2599
- })
2600
- ),
2601
- children: [
2602
- label,
2603
- isRequired && " *"
2604
- ]
2688
+ className: cn(textFieldIconVariants({ position: "trailing" })),
2689
+ "aria-hidden": "true",
2690
+ children: trailingIcon
2605
2691
  }
2606
2692
  ),
2607
- multiline ? /* @__PURE__ */ jsxRuntime.jsx(
2608
- "textarea",
2609
- {
2610
- ...inputProps,
2611
- ref: inputRef,
2612
- className: cn(
2613
- textFieldInputVariants({
2614
- variant,
2615
- size,
2616
- disabled: isDisabled,
2617
- hasLeadingIcon: !!leadingIcon,
2618
- hasTrailingIcon: !!trailingIcon,
2619
- multiline: true
2620
- }),
2621
- label && "placeholder:opacity-0"
2622
- ),
2623
- rows,
2624
- spellCheck: spellCheckProp
2625
- }
2626
- ) : /* @__PURE__ */ jsxRuntime.jsx(
2627
- "input",
2693
+ variant === "filled" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(textFieldActiveIndicatorVariants()), "aria-hidden": "true" }),
2694
+ variant === "outlined" && /* @__PURE__ */ jsxRuntime.jsx("fieldset", { "aria-hidden": "true", className: cn(textFieldOutlineVariants()), children: /* @__PURE__ */ jsxRuntime.jsx("legend", { className: cn(textFieldNotchVariants()), children: label && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2695
+ label,
2696
+ isRequired && "\u2009*"
2697
+ ] }) }) })
2698
+ ] }),
2699
+ showSupportingRow && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(textFieldSupportingRowVariants()), children: [
2700
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
2701
+ showDescription && /* @__PURE__ */ jsxRuntime.jsx(
2702
+ "p",
2703
+ {
2704
+ ...descriptionProps,
2705
+ className: cn(textFieldSupportingTextVariants({ type: "description" })),
2706
+ children: description
2707
+ }
2708
+ ),
2709
+ showError && /* @__PURE__ */ jsxRuntime.jsx(
2710
+ "p",
2711
+ {
2712
+ ...errorMessageProps,
2713
+ className: cn(textFieldSupportingTextVariants({ type: "error" })),
2714
+ children: errorMessage
2715
+ }
2716
+ )
2717
+ ] }),
2718
+ showCounter && /* @__PURE__ */ jsxRuntime.jsxs(
2719
+ "span",
2628
2720
  {
2629
- ...inputProps,
2630
- ref: inputRef,
2631
2721
  className: cn(
2632
- textFieldInputVariants({
2633
- variant,
2634
- size,
2635
- disabled: isDisabled,
2636
- hasLeadingIcon: !!leadingIcon,
2637
- hasTrailingIcon: !!trailingIcon,
2638
- multiline: false
2639
- }),
2640
- label && "placeholder:opacity-0"
2641
- // Hide placeholder when there's a value to prevent overlap with floating label
2722
+ textFieldCounterVariants({ exceeded: isCharacterLimitExceeded })
2642
2723
  ),
2643
- spellCheck: spellCheckProp
2644
- }
2645
- ),
2646
- trailingIcon && /* @__PURE__ */ jsxRuntime.jsx(
2647
- "span",
2648
- {
2649
- className: textFieldIconVariants({
2650
- position: "trailing",
2651
- size,
2652
- disabled: isDisabled
2653
- }),
2654
- children: trailingIcon
2724
+ "aria-live": "polite",
2725
+ children: [
2726
+ characterLength,
2727
+ "\u2009/\u2009",
2728
+ maxLength
2729
+ ]
2655
2730
  }
2656
2731
  )
2657
- ]
2658
- }
2659
- ),
2660
- description && !fieldIsInvalid && /* @__PURE__ */ jsxRuntime.jsx(
2661
- "div",
2662
- {
2663
- ...descriptionProps,
2664
- className: textFieldHelperTextVariants({
2665
- type: "description",
2666
- disabled: isDisabled
2667
- }),
2668
- children: description
2669
- }
2670
- ),
2671
- fieldIsInvalid && errorMessage && /* @__PURE__ */ jsxRuntime.jsx(
2672
- "div",
2673
- {
2674
- ...errorMessageProps,
2675
- className: textFieldHelperTextVariants({
2676
- type: "error",
2677
- disabled: isDisabled
2678
- }),
2679
- children: errorMessage
2680
- }
2681
- ),
2682
- characterCount && maxLength && /* @__PURE__ */ jsxRuntime.jsxs(
2683
- "div",
2684
- {
2685
- className: textFieldCharacterCountVariants({
2686
- exceeded: isCharacterLimitExceeded,
2687
- disabled: isDisabled
2688
- }),
2689
- children: [
2690
- characterLength,
2691
- " / ",
2692
- maxLength
2693
- ]
2694
- }
2695
- )
2696
- ] });
2732
+ ] })
2733
+ ]
2734
+ }
2735
+ );
2697
2736
  } });
2698
2737
  }
2699
2738
  );