@arqel-dev/fields 0.17.0 → 0.19.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/options.ts","../src/shared/styles.ts","../src/select/MultiSelectInput.tsx","../src/select/RadioGroup.tsx","../src/select/SelectInput.tsx"],"names":["cn","jsx","jsxs"],"mappings":"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","file":"select.js","sourcesContent":["/**\n * Normalises the polymorphic `options` shape on Select/Radio fields:\n * the server can emit either an array (`[{value, label}, …]`) or an\n * object (`{ value: 'Label' }`). Components only need the array form.\n */\n\nexport interface NormalisedOption {\n value: string | number;\n label: string;\n}\n\nexport function normaliseOptions(options: unknown): NormalisedOption[] {\n if (!options) return [];\n if (Array.isArray(options)) {\n return options.filter(\n (o): o is NormalisedOption =>\n typeof o === 'object' && o !== null && 'value' in o && 'label' in o,\n );\n }\n if (typeof options === 'object') {\n return Object.entries(options as Record<string, string>).map(([value, label]) => ({\n value,\n label,\n }));\n }\n return [];\n}\n","/**\n * Shared input styling — keeps the visual contract consistent across\n * every Field component without forcing a wrapper component.\n */\n\nimport { cn } from '@arqel-dev/ui/utils';\n\nexport const inputClasses = cn(\n 'h-9 w-full rounded-sm border border-[var(--input)]',\n 'bg-background px-3 text-sm text-foreground',\n 'placeholder:text-muted-foreground',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'aria-invalid:border-destructive',\n);\n\nexport const checkboxClasses = cn(\n 'h-4 w-4 rounded border-[var(--input)]',\n 'text-primary',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n);\n","/**\n * `<MultiSelectInput>` — chip-list multi-select.\n *\n * Selected items render as removable chips above the option dropdown.\n * Backed by a native `<select multiple>` for a11y; the chip strip is\n * presentation-only and writes back through the same `onChange`.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { MultiSelectFieldSchema } from '@arqel-dev/types/fields';\nimport type { FieldRendererProps } from '@arqel-dev/ui/form';\nimport { cn } from '@arqel-dev/ui/utils';\nimport { normaliseOptions } from '../shared/options.js';\nimport { inputClasses } from '../shared/styles.js';\n\nexport function MultiSelectInput({\n field,\n value,\n onChange,\n errors,\n disabled,\n inputId,\n describedBy,\n}: FieldRendererProps) {\n const f = field as MultiSelectFieldSchema;\n const t = useArqelTranslations();\n const hasError = errors !== undefined && errors.length > 0;\n const options = normaliseOptions(f.props.options);\n const arr = Array.isArray(value) ? (value as Array<string | number>) : [];\n const selectedSet = new Set(arr.map(String));\n const isDisabled = disabled || f.disabled || f.readonly;\n\n const remove = (v: string | number) => {\n onChange(arr.filter((x) => String(x) !== String(v)));\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n {arr.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {arr.map((v) => {\n const opt = options.find((o) => String(o.value) === String(v));\n return (\n <span\n key={String(v)}\n className=\"inline-flex items-center gap-1 rounded-sm bg-muted px-2 py-0.5 text-xs\"\n >\n {opt?.label ?? String(v)}\n {!isDisabled && (\n <button\n type=\"button\"\n aria-label={t('arqel.fields.multiselect.remove', 'Remove :label', {\n label: opt?.label ?? String(v),\n })}\n onClick={() => remove(v)}\n className=\"text-muted-foreground hover:text-foreground\"\n >\n ✕\n </button>\n )}\n </span>\n );\n })}\n </div>\n )}\n <select\n id={inputId}\n multiple\n className={cn(inputClasses, 'h-auto min-h-[6rem] py-1')}\n value={Array.from(selectedSet)}\n disabled={isDisabled}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n onChange={(e) => {\n const next = Array.from(e.target.selectedOptions, (o) => o.value);\n onChange(next);\n }}\n >\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n );\n}\n","/**\n * `<RadioGroup>` — radio buttons in a `role=\"radiogroup\"`.\n *\n * Honours `props.inline` to lay items out horizontally vs the default\n * stacked layout.\n */\n\nimport type { RadioFieldSchema } from '@arqel-dev/types/fields';\nimport type { FieldRendererProps } from '@arqel-dev/ui/form';\nimport { cn } from '@arqel-dev/ui/utils';\n\nexport function RadioGroup({\n field,\n value,\n onChange,\n errors,\n disabled,\n inputId,\n describedBy,\n}: FieldRendererProps) {\n const f = field as RadioFieldSchema;\n const hasError = errors !== undefined && errors.length > 0;\n const isDisabled = disabled || f.disabled || f.readonly;\n\n return (\n <div\n id={inputId}\n role=\"radiogroup\"\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n className={cn('flex gap-3', f.props.inline ? 'flex-row flex-wrap' : 'flex-col')}\n >\n {(f.props.options ?? []).map((opt) => {\n const checked = String(value ?? '') === String(opt.value);\n return (\n <label key={String(opt.value)} className=\"inline-flex items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name={f.name}\n value={String(opt.value)}\n checked={checked}\n disabled={isDisabled}\n onChange={() => onChange(opt.value)}\n className=\"h-4 w-4 border-[var(--input)] text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n","/**\n * `<SelectInput>` — single-value select.\n *\n * Phase 1 ships the native `<select>` for predictability and\n * a11y-by-default. A searchable Combobox (Base UI) variant lands in\n * FIELDS-JS-003 follow-up when `props.searchable === true`.\n */\n\nimport type { SelectFieldSchema } from '@arqel-dev/types/fields';\nimport type { FieldRendererProps } from '@arqel-dev/ui/form';\nimport { normaliseOptions } from '../shared/options.js';\nimport { inputClasses } from '../shared/styles.js';\n\nexport function SelectInput({\n field,\n value,\n onChange,\n errors,\n disabled,\n inputId,\n describedBy,\n}: FieldRendererProps) {\n const f = field as SelectFieldSchema;\n const hasError = errors !== undefined && errors.length > 0;\n const options = normaliseOptions(f.props.options);\n\n return (\n <select\n id={inputId}\n className={inputClasses}\n value={value === null || value === undefined ? '' : String(value)}\n disabled={disabled || f.disabled || f.readonly}\n required={f.required === true}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n >\n {(f.placeholder || !f.required) && <option value=\"\">{f.placeholder ?? '—'}</option>}\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/options.ts","../src/shared/styles.ts","../src/select/MultiSelectInput.tsx","../src/select/RadioGroup.tsx","../src/select/SelectInput.tsx"],"names":["cn","jsx","jsxs"],"mappings":"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","file":"select.js","sourcesContent":["/**\n * Normalises the polymorphic `options` shape on Select/Radio fields:\n * the server can emit either an array (`[{value, label}, …]`) or an\n * object (`{ value: 'Label' }`). Components only need the array form.\n */\n\nexport interface NormalisedOption {\n value: string | number;\n label: string;\n}\n\nexport function normaliseOptions(options: unknown): NormalisedOption[] {\n if (!options) return [];\n if (Array.isArray(options)) {\n return options.filter(\n (o): o is NormalisedOption =>\n typeof o === 'object' && o !== null && 'value' in o && 'label' in o,\n );\n }\n if (typeof options === 'object') {\n return Object.entries(options as Record<string, string>).map(([value, label]) => ({\n value,\n label,\n }));\n }\n return [];\n}\n","/**\n * Shared input styling — keeps the visual contract consistent across\n * every Field component without forcing a wrapper component.\n */\n\nimport { cn } from '@arqel-dev/ui/utils';\n\nexport const inputClasses = cn(\n 'h-9 w-full rounded-sm border border-[var(--input)]',\n 'bg-background px-3 text-sm text-foreground',\n 'placeholder:text-muted-foreground',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'aria-invalid:border-destructive',\n);\n\nexport const checkboxClasses = cn(\n 'h-4 w-4 rounded border-[var(--input)]',\n 'text-primary',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n);\n","/**\n * `<MultiSelectInput>` — chip-list multi-select.\n *\n * Selected items render as removable chips above the option dropdown.\n * Backed by a native `<select multiple>` for a11y; the chip strip is\n * presentation-only and writes back through the same `onChange`.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { MultiSelectFieldSchema } from '@arqel-dev/types/fields';\nimport type { FieldRendererProps } from '@arqel-dev/ui/form';\nimport { cn } from '@arqel-dev/ui/utils';\nimport { normaliseOptions } from '../shared/options.js';\nimport { inputClasses } from '../shared/styles.js';\n\nexport function MultiSelectInput({\n field,\n value,\n onChange,\n errors,\n disabled,\n inputId,\n describedBy,\n}: FieldRendererProps) {\n const f = field as MultiSelectFieldSchema;\n const t = useArqelTranslations();\n const hasError = errors !== undefined && errors.length > 0;\n const options = normaliseOptions(f.props.options);\n const arr = Array.isArray(value) ? (value as Array<string | number>) : [];\n const selectedSet = new Set(arr.map(String));\n const isDisabled = disabled || f.disabled || f.readonly;\n\n const remove = (v: string | number) => {\n onChange(arr.filter((x) => String(x) !== String(v)));\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n {arr.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {arr.map((v) => {\n const opt = options.find((o) => String(o.value) === String(v));\n return (\n <span\n key={String(v)}\n className=\"inline-flex items-center gap-1 rounded-sm bg-muted px-2 py-0.5 text-xs\"\n >\n {opt?.label ?? String(v)}\n {!isDisabled && (\n <button\n type=\"button\"\n aria-label={t('arqel.fields.multiselect.remove', 'Remove :label', {\n label: opt?.label ?? String(v),\n })}\n onClick={() => remove(v)}\n className=\"text-muted-foreground hover:text-foreground\"\n >\n ✕\n </button>\n )}\n </span>\n );\n })}\n </div>\n )}\n <select\n id={inputId}\n multiple\n className={cn(inputClasses, 'h-auto min-h-[6rem] py-1')}\n value={Array.from(selectedSet)}\n disabled={isDisabled}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n onChange={(e) => {\n const next = Array.from(e.target.selectedOptions, (o) => o.value);\n onChange(next);\n }}\n >\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n );\n}\n","/**\n * `<RadioGroup>` — radio buttons in a `role=\"radiogroup\"`.\n *\n * Honours `props.inline` to lay items out horizontally vs the default\n * stacked layout.\n */\n\nimport type { RadioFieldSchema } from '@arqel-dev/types/fields';\nimport type { FieldRendererProps } from '@arqel-dev/ui/form';\nimport { cn } from '@arqel-dev/ui/utils';\n\nexport function RadioGroup({\n field,\n value,\n onChange,\n errors,\n disabled,\n inputId,\n describedBy,\n}: FieldRendererProps) {\n const f = field as RadioFieldSchema;\n const hasError = errors !== undefined && errors.length > 0;\n const isDisabled = disabled || f.disabled || f.readonly;\n\n return (\n <div\n id={inputId}\n role=\"radiogroup\"\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n className={cn('flex gap-3', f.props.inline ? 'flex-row flex-wrap' : 'flex-col')}\n >\n {(f.props.options ?? []).map((opt) => {\n const checked = String(value ?? '') === String(opt.value);\n return (\n <label key={String(opt.value)} className=\"inline-flex items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name={f.name}\n value={String(opt.value)}\n checked={checked}\n disabled={isDisabled}\n onChange={() => onChange(opt.value)}\n className=\"h-4 w-4 border-[var(--input)] text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n","/**\n * `<SelectInput>` — single-value select.\n *\n * Phase 1 ships the native `<select>` for predictability and\n * a11y-by-default. A searchable Combobox (Base UI) variant lands in\n * FIELDS-JS-003 follow-up when `props.searchable === true`.\n */\n\nimport type { SelectFieldSchema } from '@arqel-dev/types/fields';\nimport type { FieldRendererProps } from '@arqel-dev/ui/form';\nimport { normaliseOptions } from '../shared/options.js';\nimport { inputClasses } from '../shared/styles.js';\n\nexport function SelectInput({\n field,\n value,\n onChange,\n errors,\n disabled,\n inputId,\n describedBy,\n}: FieldRendererProps) {\n const f = field as SelectFieldSchema;\n const hasError = errors !== undefined && errors.length > 0;\n const options = normaliseOptions(f.props.options);\n\n return (\n <select\n id={inputId}\n className={inputClasses}\n value={value === null || value === undefined ? '' : String(value)}\n disabled={disabled || f.disabled || f.readonly}\n required={f.required === true}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n onChange={(e) => {\n if (e.target.value === '') {\n onChange(null);\n return;\n }\n const selected = options.find((opt) => String(opt.value) === e.target.value);\n onChange(selected ? selected.value : e.target.value);\n }}\n >\n {(f.placeholder || !f.required) && <option value=\"\">{f.placeholder ?? '—'}</option>}\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arqel-dev/fields",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Rich React input components for Arqel — registered into @arqel-dev/ui's FieldRegistry.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://arqel.dev",
@@ -77,13 +77,13 @@
77
77
  "SKILL.md"
78
78
  ],
79
79
  "dependencies": {
80
- "@arqel-dev/types": "0.17.0"
80
+ "@arqel-dev/types": "0.19.0"
81
81
  },
82
82
  "peerDependencies": {
83
83
  "react": "^19.2.0",
84
84
  "react-dom": "^19.2.0",
85
- "@arqel-dev/react": "0.17.0",
86
- "@arqel-dev/ui": "0.17.0"
85
+ "@arqel-dev/react": "0.19.0",
86
+ "@arqel-dev/ui": "0.19.0"
87
87
  },
88
88
  "devDependencies": {
89
89
  "@inertiajs/react": "^3.0.0",
@@ -98,8 +98,8 @@
98
98
  "tsup": "^8.5.0",
99
99
  "typescript": "^5.6.3",
100
100
  "vitest": "^4.1.0",
101
- "@arqel-dev/react": "0.17.0",
102
- "@arqel-dev/ui": "0.17.0"
101
+ "@arqel-dev/react": "0.19.0",
102
+ "@arqel-dev/ui": "0.19.0"
103
103
  },
104
104
  "publishConfig": {
105
105
  "access": "public"