@sqrzro/ui 4.0.0-alpha.76 → 4.0.0-alpha.78

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.
@@ -5,8 +5,8 @@ import { usePathname } from 'next/navigation';
5
5
  import Switch from '../../../forms/components/Switch';
6
6
  import { useClassNames } from '../../../styles/context';
7
7
  import tw from '../../../styles/classnames/utility/tw';
8
+ import normalizeHref from '../../../utility/normalize-href';
8
9
  import Link from '../../elements/Link';
9
- import normalizeHref from '../utility/normalize-href';
10
10
  import ListItemSecondary from '../ListItemSecondary';
11
11
  import ListItemMeta from '../ListItemMeta';
12
12
  import ListItemMenu from '../ListItemMenu';
@@ -4,7 +4,7 @@ import { formatDate, formatDatetime, formatMoney, formatPoints, formatTime } fro
4
4
  import { usePathname } from 'next/navigation';
5
5
  import Link from '../../../components/elements/Link';
6
6
  import Reference from '../../../components/elements/Reference';
7
- import normalizeHref from './normalize-href';
7
+ import normalizeHref from '../../../utility/normalize-href';
8
8
  function renderDefault(value) {
9
9
  return value;
10
10
  }
@@ -4,6 +4,7 @@ export interface ChkRadClassNames {
4
4
  details: string;
5
5
  icon: CheckableClassName;
6
6
  label: string;
7
+ root: string;
7
8
  }
8
9
  export interface ChkRadProps extends ClassNameProps<ChkRadClassNames>, InputProps<boolean> {
9
10
  details?: React.ReactNode;
@@ -14,5 +15,5 @@ export interface ChkRadProps extends ClassNameProps<ChkRadClassNames>, InputProp
14
15
  * Either a checkbox or a radio button. The onChange event will return a string of the value of
15
16
  * the checked item.
16
17
  */
17
- declare function ChkRad({ classNames, classNameProps, details, id, isDisabled, name, label, onChange, type, value, }: Readonly<ChkRadProps>): React.ReactElement;
18
+ declare function ChkRad({ classNames, classNameProps, details, id, isDisabled, isReadOnly, name, label, onChange, type, value, }: Readonly<ChkRadProps>): React.ReactElement;
18
19
  export default ChkRad;
@@ -8,8 +8,11 @@ import Assistive from '../../../components/utility/Assistive';
8
8
  * Either a checkbox or a radio button. The onChange event will return a string of the value of
9
9
  * the checked item.
10
10
  */
11
- function ChkRad({ classNames, classNameProps, details, id, isDisabled, name, label, onChange, type = 'checkbox', value, }) {
12
- const componentClassNames = useClassNames('chkrad', { props: classNameProps, states: { isChecked: value ?? false } }, classNames);
11
+ function ChkRad({ classNames, classNameProps, details, id, isDisabled, isReadOnly, name, label, onChange, type = 'checkbox', value, }) {
12
+ const componentClassNames = useClassNames('chkrad', {
13
+ props: { ...classNameProps, isReadOnly: isReadOnly ?? false },
14
+ states: { isChecked: value ?? false },
15
+ }, classNames);
13
16
  const CheckedIcon = useIcon('chkrad.checked');
14
17
  const ref = useRef(null);
15
18
  function handleChange(event) {
@@ -17,6 +20,6 @@ function ChkRad({ classNames, classNameProps, details, id, isDisabled, name, lab
17
20
  onChange({ target: { name, value: event.target.checked } });
18
21
  }
19
22
  }
20
- return (_jsxs("label", { className: tw('flex cursor-pointer', isDisabled ? 'pointer-events-none opacity-30' : null), "data-testid": "chkrad-root", children: [_jsx(Assistive, { children: _jsx("input", { checked: Boolean(value), disabled: isDisabled, id: id || name, name: name, onChange: handleChange, type: type }) }), _jsx("span", { className: componentClassNames?.icon, children: CheckedIcon && value ? _jsx(CheckedIcon, {}) : null }), _jsxs("div", { ref: ref, className: tw(componentClassNames?.label), children: [label, details ? _jsx("div", { className: tw(componentClassNames?.details), children: details }) : null] })] }));
23
+ return (_jsxs("label", { className: tw(componentClassNames?.root, isDisabled ? 'pointer-events-none opacity-30' : null), children: [_jsx(Assistive, { children: _jsx("input", { checked: Boolean(value), disabled: isDisabled, id: id || name, name: name, readOnly: isReadOnly, onChange: handleChange, type: type }) }), _jsx("span", { className: componentClassNames?.icon, children: CheckedIcon && value ? _jsx(CheckedIcon, {}) : null }), _jsxs("div", { ref: ref, className: tw(componentClassNames?.label), children: [label, details ? _jsx("div", { className: tw(componentClassNames?.details), children: details }) : null] })] }));
21
24
  }
22
25
  export default ChkRad;
@@ -15,11 +15,12 @@ export interface EditableFormProps extends ClassNameProps<EditableFormClassNames
15
15
  actions?: SimpleActionObject[] | false;
16
16
  children: React.ReactNode;
17
17
  formProps: Omit<FormProps, 'children'>;
18
+ isEditable?: boolean;
18
19
  onCancel?: () => void;
19
20
  onEdit?: () => void;
20
21
  setStatus?: (status: EditingStatus | null) => void;
21
22
  status?: EditingStatus | null;
22
23
  title?: string;
23
24
  }
24
- declare function EditableForm({ classNameProps, classNames, children, formProps, onCancel, onEdit, setStatus, status, title, }: Readonly<EditableFormProps>): React.ReactElement;
25
+ declare function EditableForm({ classNameProps, classNames, children, formProps, isEditable, onCancel, onEdit, setStatus, status, title, }: Readonly<EditableFormProps>): React.ReactElement;
25
26
  export default EditableForm;
@@ -3,21 +3,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import ActionList from '../../../components/utility/ActionList';
4
4
  import { useClassNames } from '../../../styles/context';
5
5
  import Form from '../Form';
6
- function EditableForm({ classNameProps, classNames, children, formProps, onCancel, onEdit, setStatus, status, title, }) {
7
- const componentClassNames = useClassNames('editableForm', { props: classNameProps }, classNames);
6
+ function EditableForm({ classNameProps, classNames, children, formProps, isEditable = true, onCancel, onEdit, setStatus, status, title, }) {
7
+ const componentClassNames = useClassNames('editableForm', { props: { ...classNameProps, hasTitle: Boolean(title), isEditable } }, classNames);
8
8
  function setCancelled() {
9
- onCancel?.();
10
- setStatus?.('CANCELLED');
9
+ if (isEditable) {
10
+ onCancel?.();
11
+ setStatus?.('CANCELLED');
12
+ }
11
13
  }
12
14
  function setEditing() {
13
- onEdit?.();
14
- setStatus?.('EDITING');
15
+ if (isEditable) {
16
+ onEdit?.();
17
+ setStatus?.('EDITING');
18
+ }
15
19
  }
16
- return (_jsxs(Form, { ...formProps, classNames: { root: componentClassNames?.root, errors: componentClassNames?.errors }, children: [title ? (_jsx("header", { className: componentClassNames?.header, children: _jsx("legend", { className: componentClassNames?.title, children: title }) })) : null, _jsxs("div", { className: componentClassNames?.content, children: [children, _jsx("footer", { className: componentClassNames?.actions, children: _jsx(ActionList, { actions: status === 'EDITING'
20
+ return (_jsxs(Form, { ...formProps, classNames: { root: componentClassNames?.root, errors: componentClassNames?.errors }, children: [title ? (_jsx("header", { className: componentClassNames?.header, children: _jsx("legend", { className: componentClassNames?.title, children: title }) })) : null, _jsxs("div", { className: componentClassNames?.content, children: [children, isEditable ? (_jsx("footer", { className: componentClassNames?.actions, children: _jsx(ActionList, { actions: status === 'EDITING'
17
21
  ? [
18
22
  { label: 'Cancel', onClick: setCancelled },
19
23
  { isSubmittable: true, label: 'Save' },
20
24
  ]
21
- : [{ label: 'Edit', onClick: setEditing }] }) })] })] }));
25
+ : [{ label: 'Edit', onClick: setEditing }] }) })) : null] })] }));
22
26
  }
23
27
  export default EditableForm;
@@ -14,6 +14,7 @@ import PointsInput from '../PointsInput';
14
14
  import Switch from '../Switch';
15
15
  import TextArea from '../TextArea';
16
16
  import TextInput from '../TextInput';
17
+ import ChkRad from '../ChkRad';
17
18
  export function EditableCheckboxFormField(props) {
18
19
  const classNames = useClassNames('checkboxInput');
19
20
  const { fieldProps, inputProps } = extractEditableInputProps(props);
@@ -24,7 +25,7 @@ export function EditableCheckboxFormField(props) {
24
25
  }
25
26
  return (_jsx("ul", { className: classNames?.root, role: "listbox", children: props.options
26
27
  ?.filter((option) => value.includes(option.value))
27
- .map((option) => (_jsx("li", { className: classNames?.item, children: option.label }, String(option.value)))) }));
28
+ .map((option) => (_jsx("li", { className: classNames?.item, children: _jsx(ChkRad, { isReadOnly: true, label: option.label, name: props.name, value: true }) }, String(option.value)))) }));
28
29
  }, [fieldProps.value]);
29
30
  return _jsx(EditableFormField, { ...fieldProps, render: renderInput, renderValue: renderValue });
30
31
  }
@@ -6,6 +6,7 @@ export interface EditableFieldPropsReturn<Request, K extends keyof Request = key
6
6
  }
7
7
  export type UseEditableFormArgs<Request, Response> = UseFormArgs<Request, Response> & {
8
8
  defaultStatus?: EditingStatus;
9
+ isEditable?: boolean;
9
10
  onCancel?: () => void;
10
11
  onEdit?: () => void;
11
12
  title?: string;
@@ -20,5 +21,5 @@ export interface UseEditableFormReturn<Request> extends Omit<UseFormReturn<Reque
20
21
  setStatus: React.Dispatch<React.SetStateAction<EditingStatus | null>>;
21
22
  status: EditingStatus | null;
22
23
  }
23
- declare function useEditableForm<Request extends object, Response = Request>({ defaultStatus, onCancel, onEdit, onSuccess, title, ...args }: UseEditableFormArgs<Request, Response>): UseEditableFormReturn<Request>;
24
+ declare function useEditableForm<Request extends object, Response = Request>({ defaultStatus, isEditable, onCancel, onEdit, onSuccess, title, ...args }: UseEditableFormArgs<Request, Response>): UseEditableFormReturn<Request>;
24
25
  export default useEditableForm;
@@ -1,8 +1,11 @@
1
1
  import { useState } from 'react';
2
2
  import useForm from './useForm';
3
- function useEditableForm({ defaultStatus, onCancel, onEdit, onSuccess, title, ...args }) {
4
- const [status, setStatus] = useState(defaultStatus ?? null);
3
+ function useEditableForm({ defaultStatus, isEditable = true, onCancel, onEdit, onSuccess, title, ...args }) {
4
+ const [status, setStatus] = useState(isEditable ? (defaultStatus ?? null) : null);
5
5
  async function onEditableSuccess(response) {
6
+ if (!isEditable) {
7
+ return;
8
+ }
6
9
  if (onSuccess) {
7
10
  await onSuccess(response);
8
11
  }
@@ -15,7 +18,7 @@ function useEditableForm({ defaultStatus, onCancel, onEdit, onSuccess, title, ..
15
18
  });
16
19
  function editableFieldProps(name, label) {
17
20
  const fieldProps = useFormReturn.fieldProps(name, label);
18
- return { ...fieldProps, status };
21
+ return { ...fieldProps, status: isEditable ? status : null };
19
22
  }
20
23
  function handleCancel() {
21
24
  if (onCancel) {
@@ -29,6 +32,7 @@ function useEditableForm({ defaultStatus, onCancel, onEdit, onSuccess, title, ..
29
32
  fieldProps: editableFieldProps,
30
33
  formProps: {
31
34
  formProps: useFormReturn.formProps,
35
+ isEditable,
32
36
  onCancel: handleCancel,
33
37
  onEdit,
34
38
  status,
@@ -31,6 +31,7 @@ export interface InputProps<V, T extends V = V> {
31
31
  hasError?: boolean;
32
32
  id?: string;
33
33
  isDisabled?: boolean;
34
+ isReadOnly?: boolean;
34
35
  name: string;
35
36
  ref?: React.Ref<HTMLInputElement>;
36
37
  onChange?: (event: InputEvent<T>) => void;
@@ -1,5 +1,7 @@
1
- import { useRouter } from 'next/navigation';
1
+ import { usePathname, useRouter } from 'next/navigation';
2
+ import normalizeHref from '../utility/normalize-href';
2
3
  function useSuccess({ onSuccess, redirectOnSuccess, refreshOnSuccess, }) {
4
+ const pathname = usePathname();
3
5
  const router = useRouter();
4
6
  async function handleSuccess(response) {
5
7
  if (onSuccess) {
@@ -10,7 +12,7 @@ function useSuccess({ onSuccess, redirectOnSuccess, refreshOnSuccess, }) {
10
12
  ? await redirectOnSuccess(response)
11
13
  : redirectOnSuccess;
12
14
  if (url) {
13
- router.push(url);
15
+ router.push(normalizeHref(url, pathname));
14
16
  }
15
17
  }
16
18
  else if (refreshOnSuccess) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sqrzro/ui",
3
3
  "type": "module",
4
- "version": "4.0.0-alpha.76",
4
+ "version": "4.0.0-alpha.78",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "ISC",
@@ -50,15 +50,15 @@
50
50
  "dist/**/*"
51
51
  ],
52
52
  "dependencies": {
53
+ "@sqrzro/addons": "^4.0.0-alpha.14",
54
+ "@sqrzro/utility": "^4.0.0-alpha.22",
53
55
  "clsx": "^2.1.1",
54
56
  "drizzle-orm": "^0.45.2",
55
57
  "next": "^16.2.11",
56
58
  "react": "^19.2.8",
57
59
  "react-dom": "^19.2.8",
58
60
  "tailwind-merge": "^3.6.0",
59
- "use-deep-compare-effect": "^1.8.1",
60
- "@sqrzro/addons": "^4.0.0-alpha.14",
61
- "@sqrzro/utility": "^4.0.0-alpha.21"
61
+ "use-deep-compare-effect": "^1.8.1"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@storybook/addon-a11y": "^10.5.3",