@capyx/components-library 0.0.7 → 0.0.8

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,4 +1,4 @@
1
- import type { FC } from 'react';
1
+ import { type FC } from 'react';
2
2
  /**
3
3
  * Props for the TagsInput component
4
4
  */
@@ -18,9 +18,9 @@ export type TagsInputProps = {
18
18
  /** Label used in validation error messages (e.g. "Skills is required") */
19
19
  label?: string;
20
20
  /** Minimum number of tags required */
21
- minTags?: number;
21
+ min?: number;
22
22
  /** Maximum number of tags allowed */
23
- maxTags?: number;
23
+ max?: number;
24
24
  };
25
25
  /**
26
26
  * TagsInput - A multi-tag input component using Material-UI Autocomplete
@@ -31,8 +31,8 @@ export type TagsInputProps = {
31
31
  *
32
32
  * Supports validation via:
33
33
  * - **react-hook-form**: When wrapped in a `FormProvider`, the component
34
- * registers itself with `Controller` and validates `required`, `minTags`,
35
- * and `maxTags` rules automatically.
34
+ * registers itself with `Controller` and validates `required`, `min`,
35
+ * and `max` rules automatically.
36
36
  * - **Native HTML5**: A hidden `<input>` element participates in native
37
37
  * constraint validation (`required` attribute), making it compatible with
38
38
  * any form library that relies on `checkValidity()` / `reportValidity()`.
@@ -45,8 +45,8 @@ export type TagsInputProps = {
45
45
  * onChange={setTags}
46
46
  * placeholder="Add skills..."
47
47
  * required
48
- * minTags={1}
49
- * maxTags={5}
48
+ * min={1}
49
+ * max={5}
50
50
  * />
51
51
  * ```
52
52
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TagsInput.d.ts","sourceRoot":"","sources":["../../lib/components/TagsInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CAuNxC,CAAC"}
1
+ {"version":3,"file":"TagsInput.d.ts","sourceRoot":"","sources":["../../lib/components/TagsInput.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,EAAqB,MAAM,OAAO,CAAC;AAGnD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CAgPxC,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createElement as _createElement } from "react";
3
3
  import { Autocomplete, Chip, FormHelperText, TextField } from '@mui/material';
4
+ import { useEffect, useRef } from 'react';
4
5
  import { Controller, useFormContext } from 'react-hook-form';
5
6
  /**
6
7
  * TagsInput - A multi-tag input component using Material-UI Autocomplete
@@ -11,8 +12,8 @@ import { Controller, useFormContext } from 'react-hook-form';
11
12
  *
12
13
  * Supports validation via:
13
14
  * - **react-hook-form**: When wrapped in a `FormProvider`, the component
14
- * registers itself with `Controller` and validates `required`, `minTags`,
15
- * and `maxTags` rules automatically.
15
+ * registers itself with `Controller` and validates `required`, `min`,
16
+ * and `max` rules automatically.
16
17
  * - **Native HTML5**: A hidden `<input>` element participates in native
17
18
  * constraint validation (`required` attribute), making it compatible with
18
19
  * any form library that relies on `checkValidity()` / `reportValidity()`.
@@ -25,13 +26,35 @@ import { Controller, useFormContext } from 'react-hook-form';
25
26
  * onChange={setTags}
26
27
  * placeholder="Add skills..."
27
28
  * required
28
- * minTags={1}
29
- * maxTags={5}
29
+ * min={1}
30
+ * max={5}
30
31
  * />
31
32
  * ```
32
33
  */
33
- export const TagsInput = ({ name, value: valueProp = [], onChange, placeholder = 'Add tags...', disabled = false, required = false, label, minTags, maxTags, }) => {
34
+ export const TagsInput = ({ name, value: valueProp = [], onChange, placeholder = 'Add tags...', disabled = false, required = false, label, min, max, }) => {
34
35
  const formContext = useFormContext();
36
+ const nativeInputRef = useRef(null);
37
+ const fieldLabel = label || 'This field';
38
+ // Keep the hidden native input's custom validity in sync with the tag count
39
+ // so that form.checkValidity() / form.reportValidity() report the right error.
40
+ useEffect(() => {
41
+ const input = nativeInputRef.current;
42
+ if (!input)
43
+ return;
44
+ const count = valueProp.length;
45
+ if (required && count === 0) {
46
+ input.setCustomValidity(`${fieldLabel} is required`);
47
+ }
48
+ else if (min != null && count < min) {
49
+ input.setCustomValidity(`At least ${min} tag${min === 1 ? '' : 's'} required`);
50
+ }
51
+ else if (max != null && count > max) {
52
+ input.setCustomValidity(`No more than ${max} tag${max === 1 ? '' : 's'} allowed`);
53
+ }
54
+ else {
55
+ input.setCustomValidity('');
56
+ }
57
+ }, [valueProp, required, min, max, fieldLabel]);
35
58
  const getFieldError = (fieldName) => {
36
59
  try {
37
60
  const error = formContext?.formState?.errors?.[fieldName];
@@ -41,20 +64,19 @@ export const TagsInput = ({ name, value: valueProp = [], onChange, placeholder =
41
64
  return undefined;
42
65
  }
43
66
  };
44
- const fieldLabel = label || 'This field';
45
67
  const buildRules = () => ({
46
68
  required: required ? `${fieldLabel} is required` : false,
47
69
  validate: {
48
- ...(minTags != null
70
+ ...(min != null
49
71
  ? {
50
- minTags: (v) => v.length >= minTags ||
51
- `At least ${minTags} tag${minTags === 1 ? '' : 's'} required`,
72
+ min: (v) => v.length >= min ||
73
+ `At least ${min} tag${min === 1 ? '' : 's'} required`,
52
74
  }
53
75
  : {}),
54
- ...(maxTags != null
76
+ ...(max != null
55
77
  ? {
56
- maxTags: (v) => v.length <= maxTags ||
57
- `No more than ${maxTags} tag${maxTags === 1 ? '' : 's'} allowed`,
78
+ max: (v) => v.length <= max ||
79
+ `No more than ${max} tag${max === 1 ? '' : 's'} allowed`,
58
80
  }
59
81
  : {}),
60
82
  },
@@ -63,9 +85,9 @@ export const TagsInput = ({ name, value: valueProp = [], onChange, placeholder =
63
85
  const cleaned = newValue
64
86
  .map((v) => (typeof v === 'string' ? v.trim() : v))
65
87
  .filter((v) => v.length > 0);
66
- // Enforce maxTags cap
67
- if (maxTags != null && cleaned.length > maxTags) {
68
- return cleaned.slice(0, maxTags);
88
+ // Enforce max cap
89
+ if (max != null && cleaned.length > max) {
90
+ return cleaned.slice(0, max);
69
91
  }
70
92
  return cleaned;
71
93
  };
@@ -126,8 +148,7 @@ export const TagsInput = ({ name, value: valueProp = [], onChange, placeholder =
126
148
  return (_jsxs("div", { children: [_jsx(Autocomplete, { multiple: true, freeSolo: true, options: [], value: valueProp, onChange: (_event, newValue) => {
127
149
  const cleaned = cleanValues(newValue);
128
150
  onChange?.(cleaned);
129
- }, disabled: disabled, renderValue: (tagValue, getTagProps) => renderChips(tagValue, getTagProps), renderInput: (params) => (_jsx(TextField, { ...params, name: name, placeholder: valueProp.length === 0 ? placeholder : undefined, variant: "outlined", size: "small", sx: inputSx(false) })) }), _jsx("input", { type: "text", name: `${name}__native`, value: valueProp.join(','), required: required, "aria-hidden": "true", tabIndex: -1, onChange: () => { }, style: {
130
- display: 'none',
151
+ }, disabled: disabled, renderValue: (tagValue, getTagProps) => renderChips(tagValue, getTagProps), renderInput: (params) => (_jsx(TextField, { ...params, name: name, placeholder: valueProp.length === 0 ? placeholder : undefined, variant: "outlined", size: "small", sx: inputSx(false) })) }), _jsx("input", { ref: nativeInputRef, type: "text", name: `${name}__native`, value: valueProp.join(','), "aria-hidden": "true", tabIndex: -1, onChange: () => { }, style: {
131
152
  position: 'absolute',
132
153
  width: 0,
133
154
  height: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capyx/components-library",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Capyx Components Library for forms across applications",
5
5
  "publishConfig": {
6
6
  "access": "public"