1
0

fields.tsx 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. 'use client';
  2. import { useId } from 'react';
  3. const inputClass =
  4. 'rounded-lg border bg-fd-background px-3 py-2 text-sm outline-none transition-colors focus-visible:border-fd-primary focus-visible:ring-2 focus-visible:ring-fd-ring/30';
  5. export function TextField({
  6. label,
  7. value,
  8. onChange,
  9. placeholder,
  10. hint,
  11. inputMode,
  12. }: {
  13. label: string;
  14. value: string;
  15. onChange: (value: string) => void;
  16. placeholder?: string;
  17. hint?: string;
  18. inputMode?: 'numeric' | 'text';
  19. }) {
  20. const id = useId();
  21. return (
  22. <div className="flex flex-col gap-1.5">
  23. <label htmlFor={id} className="text-sm font-medium">
  24. {label}
  25. </label>
  26. {/* Values are technical (hosts, links) and stay LTR even on RTL pages. */}
  27. <input
  28. id={id}
  29. dir="ltr"
  30. inputMode={inputMode}
  31. value={value}
  32. placeholder={placeholder}
  33. onChange={(e) => onChange(e.target.value)}
  34. className={inputClass}
  35. />
  36. {hint ? <span className="text-xs text-fd-muted-foreground">{hint}</span> : null}
  37. </div>
  38. );
  39. }
  40. export function CheckboxField({
  41. label,
  42. checked,
  43. onChange,
  44. }: {
  45. label: string;
  46. checked: boolean;
  47. onChange: (checked: boolean) => void;
  48. }) {
  49. const id = useId();
  50. return (
  51. <label htmlFor={id} className="inline-flex cursor-pointer items-center gap-2 text-sm">
  52. <input
  53. id={id}
  54. type="checkbox"
  55. checked={checked}
  56. onChange={(e) => onChange(e.target.checked)}
  57. className="size-4 accent-fd-primary"
  58. />
  59. {label}
  60. </label>
  61. );
  62. }
  63. export function SelectField({
  64. label,
  65. value,
  66. onChange,
  67. options,
  68. }: {
  69. label: string;
  70. value: string;
  71. onChange: (value: string) => void;
  72. options: readonly string[];
  73. }) {
  74. const id = useId();
  75. return (
  76. <div className="flex flex-col gap-1.5">
  77. <label htmlFor={id} className="text-sm font-medium">
  78. {label}
  79. </label>
  80. <select
  81. id={id}
  82. value={value}
  83. onChange={(e) => onChange(e.target.value)}
  84. className={inputClass}
  85. >
  86. {options.map((opt) => (
  87. <option key={opt} value={opt}>
  88. {opt}
  89. </option>
  90. ))}
  91. </select>
  92. </div>
  93. );
  94. }