@launchpad-ui/inline-edit 0.2.10 → 0.2.11

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.es.js CHANGED
@@ -12,144 +12,148 @@ import { forwardRef, useState, useRef, cloneElement, Children } from "react";
12
12
  import { createRuntimeFn } from "@vanilla-extract/recipes/createRuntimeFn";
13
13
  var cancelButton = "_1oig0624";
14
14
  var container = "_1oig0620";
15
- var inline = createRuntimeFn({
16
- defaultClassName: "_1oig0621",
17
- variantClassNames: {
18
- layout: {
19
- vertical: "_1oig0622",
20
- horizontal: "_1oig0623"
21
- }
22
- },
23
- defaultVariants: {},
24
- compoundVariants: []
25
- });
15
+ var inline = createRuntimeFn({ defaultClassName: "_1oig0621", variantClassNames: { layout: { vertical: "_1oig0622", horizontal: "_1oig0623" } }, defaultVariants: {}, compoundVariants: [] });
26
16
  var readButton = "_1oig0625";
27
- const InlineEdit = /* @__PURE__ */ forwardRef(({
28
- "data-test-id": testId = "inline-edit",
29
- layout = "horizontal",
30
- children,
31
- defaultValue,
32
- onConfirm,
33
- hideEdit = false,
34
- renderInput = /* @__PURE__ */ jsx(TextField, {}),
35
- "aria-label": ariaLabel,
36
- isEditing: isEditingProp,
37
- onCancel,
38
- onEdit,
39
- cancelButtonLabel = "cancel",
40
- editButtonLabel = "edit",
41
- confirmButtonLabel = "confirm",
42
- className,
43
- ...rest
44
- }, ref) => {
45
- const [isEditing, setEditing] = useState(isEditingProp ?? false);
46
- const [isFocusWithin, setFocusWithin] = useState(false);
47
- const inputRef = useRef(null);
48
- const editRef = useRef(null);
49
- const controlled = isEditingProp !== void 0;
50
- useUpdateEffect(() => {
51
- if (controlled) {
52
- setEditing(isEditingProp);
53
- }
54
- }, [isEditingProp]);
55
- useUpdateEffect(() => {
56
- if (isFocusWithin) {
57
- isEditing ? inputRef.current && focusSafely(inputRef.current) : editRef.current && focusSafely(editRef.current);
58
- }
59
- }, [isEditing]);
60
- const handleEdit = () => {
61
- !controlled && setEditing(true);
62
- onEdit == null ? void 0 : onEdit();
63
- };
64
- const handleCancel = () => {
65
- !controlled && setEditing(false);
66
- onCancel == null ? void 0 : onCancel();
67
- };
68
- const handleConfirm = () => {
69
- var _a;
70
- onConfirm(((_a = inputRef.current) == null ? void 0 : _a.value) || "");
71
- !controlled && setEditing(false);
72
- };
73
- const handleKeyDown = (event) => {
74
- if (event.key === "Enter") {
75
- event.preventDefault();
76
- handleConfirm();
77
- } else if (event.key === "Escape") {
78
- event.preventDefault();
79
- handleCancel();
80
- }
81
- };
82
- const {
83
- focusWithinProps
84
- } = useFocusWithin({
85
- onBlurWithin: () => isEditing && handleCancel(),
86
- onFocusWithinChange: (isFocusWithin2) => setFocusWithin(isFocusWithin2)
87
- });
88
- const {
89
- buttonProps
90
- } = useButton({
91
- "aria-label": editButtonLabel,
92
- elementType: "span",
93
- onPress: handleEdit
94
- }, editRef);
95
- const renderReadContent = hideEdit ? /* @__PURE__ */ jsx("span", {
96
- ref: editRef,
97
- ...buttonProps,
98
- className: readButton,
99
- children
100
- }) : /* @__PURE__ */ jsxs(Fragment, {
101
- children: [children, /* @__PURE__ */ jsx(IconButton, {
102
- ref: editRef,
103
- icon: /* @__PURE__ */ jsx(Icon, {
104
- name: "edit"
105
- }),
106
- "aria-label": editButtonLabel,
107
- size: "small",
108
- onClick: handleEdit
109
- })]
110
- });
111
- const inputProps = {
112
- ref: mergeRefs(inputRef, ref),
17
+ const InlineEdit = /* @__PURE__ */ forwardRef(
18
+ ({
19
+ "data-test-id": testId = "inline-edit",
20
+ layout = "horizontal",
21
+ children,
113
22
  defaultValue,
114
- onKeyDown: handleKeyDown,
115
- "aria-label": ariaLabel
116
- };
117
- const inputChildren = renderInput.props.children;
118
- const input = /* @__PURE__ */ cloneElement(renderInput, mergeProps(renderInput.props, inputChildren ? {} : inputProps), inputChildren && Children.map(inputChildren, (child) => child.type === TextField || child.type === TextArea ? /* @__PURE__ */ cloneElement(child, mergeProps(child.props, inputProps)) : child));
119
- return isEditing ? /* @__PURE__ */ jsxs("div", {
120
- ...rest,
121
- className: cx(container, inline({
122
- layout
123
- }), className),
124
- "data-test-id": testId,
125
- ...focusWithinProps,
126
- children: [input, /* @__PURE__ */ jsxs(ButtonGroup, {
127
- spacing: "compact",
128
- children: [/* @__PURE__ */ jsx(IconButton, {
129
- kind: "primary",
130
- icon: /* @__PURE__ */ jsx(Icon, {
131
- name: "check"
132
- }),
133
- "aria-label": confirmButtonLabel,
134
- onClick: handleConfirm
135
- }), /* @__PURE__ */ jsx(IconButton, {
136
- kind: "default",
137
- icon: /* @__PURE__ */ jsx(Icon, {
138
- name: "cancel"
139
- }),
140
- "aria-label": cancelButtonLabel,
141
- className: cancelButton,
142
- onClick: handleCancel
143
- })]
144
- })]
145
- }) : /* @__PURE__ */ jsx("div", {
146
- ...rest,
147
- className: cx(!hideEdit && container, className),
148
- "data-test-id": testId,
149
- ...focusWithinProps,
150
- children: renderReadContent
151
- });
152
- });
23
+ onConfirm,
24
+ hideEdit = false,
25
+ renderInput = /* @__PURE__ */ jsx(TextField, {}),
26
+ "aria-label": ariaLabel,
27
+ isEditing: isEditingProp,
28
+ onCancel,
29
+ onEdit,
30
+ cancelButtonLabel = "cancel",
31
+ editButtonLabel = "edit",
32
+ confirmButtonLabel = "confirm",
33
+ className,
34
+ ...rest
35
+ }, ref) => {
36
+ const [isEditing, setEditing] = useState(isEditingProp ?? false);
37
+ const [isFocusWithin, setFocusWithin] = useState(false);
38
+ const inputRef = useRef(null);
39
+ const editRef = useRef(null);
40
+ const controlled = isEditingProp !== void 0;
41
+ useUpdateEffect(() => {
42
+ if (controlled) {
43
+ setEditing(isEditingProp);
44
+ }
45
+ }, [isEditingProp]);
46
+ useUpdateEffect(() => {
47
+ if (isFocusWithin) {
48
+ isEditing ? inputRef.current && focusSafely(inputRef.current) : editRef.current && focusSafely(editRef.current);
49
+ }
50
+ }, [isEditing]);
51
+ const handleEdit = () => {
52
+ !controlled && setEditing(true);
53
+ onEdit == null ? void 0 : onEdit();
54
+ };
55
+ const handleCancel = () => {
56
+ !controlled && setEditing(false);
57
+ onCancel == null ? void 0 : onCancel();
58
+ };
59
+ const handleConfirm = () => {
60
+ var _a;
61
+ onConfirm(((_a = inputRef.current) == null ? void 0 : _a.value) || "");
62
+ !controlled && setEditing(false);
63
+ };
64
+ const handleKeyDown = (event) => {
65
+ if (event.key === "Enter") {
66
+ event.preventDefault();
67
+ handleConfirm();
68
+ } else if (event.key === "Escape") {
69
+ event.preventDefault();
70
+ handleCancel();
71
+ }
72
+ };
73
+ const { focusWithinProps } = useFocusWithin({
74
+ onBlurWithin: () => isEditing && handleCancel(),
75
+ onFocusWithinChange: (isFocusWithin2) => setFocusWithin(isFocusWithin2)
76
+ });
77
+ const { buttonProps } = useButton(
78
+ {
79
+ "aria-label": editButtonLabel,
80
+ elementType: "span",
81
+ onPress: handleEdit
82
+ },
83
+ editRef
84
+ );
85
+ const renderReadContent = hideEdit ? /* @__PURE__ */ jsx("span", { ref: editRef, ...buttonProps, className: readButton, children }) : /* @__PURE__ */ jsxs(Fragment, { children: [
86
+ children,
87
+ /* @__PURE__ */ jsx(
88
+ IconButton,
89
+ {
90
+ ref: editRef,
91
+ icon: /* @__PURE__ */ jsx(Icon, { name: "edit" }),
92
+ "aria-label": editButtonLabel,
93
+ size: "small",
94
+ onClick: handleEdit
95
+ }
96
+ )
97
+ ] });
98
+ const inputProps = {
99
+ ref: mergeRefs(inputRef, ref),
100
+ defaultValue,
101
+ onKeyDown: handleKeyDown,
102
+ "aria-label": ariaLabel
103
+ };
104
+ const inputChildren = renderInput.props.children;
105
+ const input = /* @__PURE__ */ cloneElement(
106
+ renderInput,
107
+ mergeProps(renderInput.props, inputChildren ? {} : inputProps),
108
+ inputChildren && Children.map(
109
+ inputChildren,
110
+ (child) => child.type === TextField || child.type === TextArea ? /* @__PURE__ */ cloneElement(child, mergeProps(child.props, inputProps)) : child
111
+ )
112
+ );
113
+ return isEditing ? /* @__PURE__ */ jsxs(
114
+ "div",
115
+ {
116
+ ...rest,
117
+ className: cx(container, inline({ layout }), className),
118
+ "data-test-id": testId,
119
+ ...focusWithinProps,
120
+ children: [
121
+ input,
122
+ /* @__PURE__ */ jsxs(ButtonGroup, { spacing: "compact", children: [
123
+ /* @__PURE__ */ jsx(
124
+ IconButton,
125
+ {
126
+ kind: "primary",
127
+ icon: /* @__PURE__ */ jsx(Icon, { name: "check" }),
128
+ "aria-label": confirmButtonLabel,
129
+ onClick: handleConfirm
130
+ }
131
+ ),
132
+ /* @__PURE__ */ jsx(
133
+ IconButton,
134
+ {
135
+ kind: "default",
136
+ icon: /* @__PURE__ */ jsx(Icon, { name: "cancel" }),
137
+ "aria-label": cancelButtonLabel,
138
+ className: cancelButton,
139
+ onClick: handleCancel
140
+ }
141
+ )
142
+ ] })
143
+ ]
144
+ }
145
+ ) : /* @__PURE__ */ jsx(
146
+ "div",
147
+ {
148
+ ...rest,
149
+ className: cx(!hideEdit && container, className),
150
+ "data-test-id": testId,
151
+ ...focusWithinProps,
152
+ children: renderReadContent
153
+ }
154
+ );
155
+ }
156
+ );
153
157
  InlineEdit.displayName = "InlineEdit";
154
158
  export {
155
159
  InlineEdit
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/InlineEdit.tsx"],"sourcesContent":["import type { InlineVariants } from './styles/InlineEdit.css';\nimport type { IconFieldProps, TextAreaProps, TextFieldProps } from '@launchpad-ui/form';\nimport type { ComponentProps, KeyboardEventHandler, ReactElement } from 'react';\n\nimport { ButtonGroup, IconButton } from '@launchpad-ui/button';\nimport { TextField, TextArea } from '@launchpad-ui/form';\nimport { Icon } from '@launchpad-ui/icons';\nimport { useButton } from '@react-aria/button';\nimport { focusSafely } from '@react-aria/focus';\nimport { useFocusWithin } from '@react-aria/interactions';\nimport { mergeProps, mergeRefs, useUpdateEffect } from '@react-aria/utils';\nimport { cx } from 'classix';\nimport { Children, cloneElement, forwardRef, useRef, useState } from 'react';\n\nimport { container, cancelButton, inline, readButton } from './styles/InlineEdit.css';\n\ntype InlineEditProps = ComponentProps<'div'> &\n InlineVariants &\n Pick<ComponentProps<'input'>, 'defaultValue'> & {\n 'data-test-id'?: string;\n onConfirm: (value: string) => void;\n hideEdit?: boolean;\n renderInput?: ReactElement<IconFieldProps | TextFieldProps | TextAreaProps>;\n isEditing?: boolean;\n onCancel?: () => void;\n onEdit?: () => void;\n cancelButtonLabel?: string;\n editButtonLabel?: string;\n confirmButtonLabel?: string;\n };\n\nconst InlineEdit = forwardRef<HTMLInputElement, InlineEditProps>(\n (\n {\n 'data-test-id': testId = 'inline-edit',\n layout = 'horizontal',\n children,\n defaultValue,\n onConfirm,\n hideEdit = false,\n renderInput = <TextField />,\n 'aria-label': ariaLabel,\n isEditing: isEditingProp,\n onCancel,\n onEdit,\n cancelButtonLabel = 'cancel',\n editButtonLabel = 'edit',\n confirmButtonLabel = 'confirm',\n className,\n ...rest\n },\n ref\n ) => {\n const [isEditing, setEditing] = useState(isEditingProp ?? false);\n const [isFocusWithin, setFocusWithin] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const editRef = useRef<HTMLButtonElement>(null);\n const controlled = isEditingProp !== undefined;\n\n useUpdateEffect(() => {\n if (controlled) {\n setEditing(isEditingProp);\n }\n }, [isEditingProp]);\n\n useUpdateEffect(() => {\n if (isFocusWithin) {\n isEditing\n ? inputRef.current && focusSafely(inputRef.current)\n : editRef.current && focusSafely(editRef.current);\n }\n }, [isEditing]);\n\n const handleEdit = () => {\n !controlled && setEditing(true);\n onEdit?.();\n };\n\n const handleCancel = () => {\n !controlled && setEditing(false);\n onCancel?.();\n };\n\n const handleConfirm = () => {\n onConfirm(inputRef.current?.value || '');\n !controlled && setEditing(false);\n };\n\n const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n handleConfirm();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n handleCancel();\n }\n };\n\n const { focusWithinProps } = useFocusWithin({\n onBlurWithin: () => isEditing && handleCancel(),\n onFocusWithinChange: (isFocusWithin) => setFocusWithin(isFocusWithin),\n });\n\n const { buttonProps } = useButton(\n {\n 'aria-label': editButtonLabel,\n elementType: 'span',\n onPress: handleEdit,\n },\n editRef\n );\n\n const renderReadContent = hideEdit ? (\n <span ref={editRef} {...buttonProps} className={readButton}>\n {children}\n </span>\n ) : (\n <>\n {children}\n <IconButton\n ref={editRef}\n icon={<Icon name=\"edit\" />}\n aria-label={editButtonLabel}\n size=\"small\"\n onClick={handleEdit}\n />\n </>\n );\n\n const inputProps = {\n ref: mergeRefs(inputRef, ref),\n defaultValue,\n onKeyDown: handleKeyDown,\n 'aria-label': ariaLabel,\n };\n\n const inputChildren = renderInput.props.children;\n\n const input = cloneElement(\n renderInput,\n mergeProps(renderInput.props, inputChildren ? {} : inputProps),\n inputChildren &&\n Children.map(inputChildren, (child) =>\n child.type === TextField || child.type === TextArea\n ? cloneElement(child, mergeProps(child.props, inputProps))\n : child\n )\n );\n\n return isEditing ? (\n <div\n {...rest}\n className={cx(container, inline({ layout }), className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {input}\n <ButtonGroup spacing=\"compact\">\n <IconButton\n kind=\"primary\"\n icon={<Icon name=\"check\" />}\n aria-label={confirmButtonLabel}\n onClick={handleConfirm}\n />\n <IconButton\n kind=\"default\"\n icon={<Icon name=\"cancel\" />}\n aria-label={cancelButtonLabel}\n className={cancelButton}\n onClick={handleCancel}\n />\n </ButtonGroup>\n </div>\n ) : (\n <div\n {...rest}\n className={cx(!hideEdit && container, className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {renderReadContent}\n </div>\n );\n }\n);\n\nInlineEdit.displayName = 'InlineEdit';\n\nexport { InlineEdit };\nexport type { InlineEditProps };\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/InlineEdit.tsx"],"sourcesContent":["import type { InlineVariants } from './styles/InlineEdit.css';\nimport type { IconFieldProps, TextAreaProps, TextFieldProps } from '@launchpad-ui/form';\nimport type { ComponentProps, KeyboardEventHandler, ReactElement } from 'react';\n\nimport { ButtonGroup, IconButton } from '@launchpad-ui/button';\nimport { TextField, TextArea } from '@launchpad-ui/form';\nimport { Icon } from '@launchpad-ui/icons';\nimport { useButton } from '@react-aria/button';\nimport { focusSafely } from '@react-aria/focus';\nimport { useFocusWithin } from '@react-aria/interactions';\nimport { mergeProps, mergeRefs, useUpdateEffect } from '@react-aria/utils';\nimport { cx } from 'classix';\nimport { Children, cloneElement, forwardRef, useRef, useState } from 'react';\n\nimport { container, cancelButton, inline, readButton } from './styles/InlineEdit.css';\n\ntype InlineEditProps = ComponentProps<'div'> &\n InlineVariants &\n Pick<ComponentProps<'input'>, 'defaultValue'> & {\n 'data-test-id'?: string;\n onConfirm: (value: string) => void;\n hideEdit?: boolean;\n renderInput?: ReactElement<IconFieldProps | TextFieldProps | TextAreaProps>;\n isEditing?: boolean;\n onCancel?: () => void;\n onEdit?: () => void;\n cancelButtonLabel?: string;\n editButtonLabel?: string;\n confirmButtonLabel?: string;\n };\n\nconst InlineEdit = forwardRef<HTMLInputElement, InlineEditProps>(\n (\n {\n 'data-test-id': testId = 'inline-edit',\n layout = 'horizontal',\n children,\n defaultValue,\n onConfirm,\n hideEdit = false,\n renderInput = <TextField />,\n 'aria-label': ariaLabel,\n isEditing: isEditingProp,\n onCancel,\n onEdit,\n cancelButtonLabel = 'cancel',\n editButtonLabel = 'edit',\n confirmButtonLabel = 'confirm',\n className,\n ...rest\n },\n ref\n ) => {\n const [isEditing, setEditing] = useState(isEditingProp ?? false);\n const [isFocusWithin, setFocusWithin] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const editRef = useRef<HTMLButtonElement>(null);\n const controlled = isEditingProp !== undefined;\n\n useUpdateEffect(() => {\n if (controlled) {\n setEditing(isEditingProp);\n }\n }, [isEditingProp]);\n\n useUpdateEffect(() => {\n if (isFocusWithin) {\n isEditing\n ? inputRef.current && focusSafely(inputRef.current)\n : editRef.current && focusSafely(editRef.current);\n }\n }, [isEditing]);\n\n const handleEdit = () => {\n !controlled && setEditing(true);\n onEdit?.();\n };\n\n const handleCancel = () => {\n !controlled && setEditing(false);\n onCancel?.();\n };\n\n const handleConfirm = () => {\n onConfirm(inputRef.current?.value || '');\n !controlled && setEditing(false);\n };\n\n const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n handleConfirm();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n handleCancel();\n }\n };\n\n const { focusWithinProps } = useFocusWithin({\n onBlurWithin: () => isEditing && handleCancel(),\n onFocusWithinChange: (isFocusWithin) => setFocusWithin(isFocusWithin),\n });\n\n const { buttonProps } = useButton(\n {\n 'aria-label': editButtonLabel,\n elementType: 'span',\n onPress: handleEdit,\n },\n editRef\n );\n\n const renderReadContent = hideEdit ? (\n <span ref={editRef} {...buttonProps} className={readButton}>\n {children}\n </span>\n ) : (\n <>\n {children}\n <IconButton\n ref={editRef}\n icon={<Icon name=\"edit\" />}\n aria-label={editButtonLabel}\n size=\"small\"\n onClick={handleEdit}\n />\n </>\n );\n\n const inputProps = {\n ref: mergeRefs(inputRef, ref),\n defaultValue,\n onKeyDown: handleKeyDown,\n 'aria-label': ariaLabel,\n };\n\n const inputChildren = renderInput.props.children;\n\n const input = cloneElement(\n renderInput,\n mergeProps(renderInput.props, inputChildren ? {} : inputProps),\n inputChildren &&\n Children.map(inputChildren, (child) =>\n child.type === TextField || child.type === TextArea\n ? cloneElement(child, mergeProps(child.props, inputProps))\n : child\n )\n );\n\n return isEditing ? (\n <div\n {...rest}\n className={cx(container, inline({ layout }), className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {input}\n <ButtonGroup spacing=\"compact\">\n <IconButton\n kind=\"primary\"\n icon={<Icon name=\"check\" />}\n aria-label={confirmButtonLabel}\n onClick={handleConfirm}\n />\n <IconButton\n kind=\"default\"\n icon={<Icon name=\"cancel\" />}\n aria-label={cancelButtonLabel}\n className={cancelButton}\n onClick={handleCancel}\n />\n </ButtonGroup>\n </div>\n ) : (\n <div\n {...rest}\n className={cx(!hideEdit && container, className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {renderReadContent}\n </div>\n );\n }\n);\n\nInlineEdit.displayName = 'InlineEdit';\n\nexport { InlineEdit };\nexport type { InlineEditProps };\n"],"names":["isFocusWithin"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -14,144 +14,148 @@ const react = require("react");
14
14
  const createRuntimeFn = require("@vanilla-extract/recipes/createRuntimeFn");
15
15
  var cancelButton = "_1oig0624";
16
16
  var container = "_1oig0620";
17
- var inline = createRuntimeFn.createRuntimeFn({
18
- defaultClassName: "_1oig0621",
19
- variantClassNames: {
20
- layout: {
21
- vertical: "_1oig0622",
22
- horizontal: "_1oig0623"
23
- }
24
- },
25
- defaultVariants: {},
26
- compoundVariants: []
27
- });
17
+ var inline = createRuntimeFn.createRuntimeFn({ defaultClassName: "_1oig0621", variantClassNames: { layout: { vertical: "_1oig0622", horizontal: "_1oig0623" } }, defaultVariants: {}, compoundVariants: [] });
28
18
  var readButton = "_1oig0625";
29
- const InlineEdit = /* @__PURE__ */ react.forwardRef(({
30
- "data-test-id": testId = "inline-edit",
31
- layout = "horizontal",
32
- children,
33
- defaultValue,
34
- onConfirm,
35
- hideEdit = false,
36
- renderInput = /* @__PURE__ */ jsxRuntime.jsx(form.TextField, {}),
37
- "aria-label": ariaLabel,
38
- isEditing: isEditingProp,
39
- onCancel,
40
- onEdit,
41
- cancelButtonLabel = "cancel",
42
- editButtonLabel = "edit",
43
- confirmButtonLabel = "confirm",
44
- className,
45
- ...rest
46
- }, ref) => {
47
- const [isEditing, setEditing] = react.useState(isEditingProp ?? false);
48
- const [isFocusWithin, setFocusWithin] = react.useState(false);
49
- const inputRef = react.useRef(null);
50
- const editRef = react.useRef(null);
51
- const controlled = isEditingProp !== void 0;
52
- utils.useUpdateEffect(() => {
53
- if (controlled) {
54
- setEditing(isEditingProp);
55
- }
56
- }, [isEditingProp]);
57
- utils.useUpdateEffect(() => {
58
- if (isFocusWithin) {
59
- isEditing ? inputRef.current && focus.focusSafely(inputRef.current) : editRef.current && focus.focusSafely(editRef.current);
60
- }
61
- }, [isEditing]);
62
- const handleEdit = () => {
63
- !controlled && setEditing(true);
64
- onEdit == null ? void 0 : onEdit();
65
- };
66
- const handleCancel = () => {
67
- !controlled && setEditing(false);
68
- onCancel == null ? void 0 : onCancel();
69
- };
70
- const handleConfirm = () => {
71
- var _a;
72
- onConfirm(((_a = inputRef.current) == null ? void 0 : _a.value) || "");
73
- !controlled && setEditing(false);
74
- };
75
- const handleKeyDown = (event) => {
76
- if (event.key === "Enter") {
77
- event.preventDefault();
78
- handleConfirm();
79
- } else if (event.key === "Escape") {
80
- event.preventDefault();
81
- handleCancel();
82
- }
83
- };
84
- const {
85
- focusWithinProps
86
- } = interactions.useFocusWithin({
87
- onBlurWithin: () => isEditing && handleCancel(),
88
- onFocusWithinChange: (isFocusWithin2) => setFocusWithin(isFocusWithin2)
89
- });
90
- const {
91
- buttonProps
92
- } = button.useButton({
93
- "aria-label": editButtonLabel,
94
- elementType: "span",
95
- onPress: handleEdit
96
- }, editRef);
97
- const renderReadContent = hideEdit ? /* @__PURE__ */ jsxRuntime.jsx("span", {
98
- ref: editRef,
99
- ...buttonProps,
100
- className: readButton,
101
- children
102
- }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
103
- children: [children, /* @__PURE__ */ jsxRuntime.jsx(button$1.IconButton, {
104
- ref: editRef,
105
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, {
106
- name: "edit"
107
- }),
108
- "aria-label": editButtonLabel,
109
- size: "small",
110
- onClick: handleEdit
111
- })]
112
- });
113
- const inputProps = {
114
- ref: utils.mergeRefs(inputRef, ref),
19
+ const InlineEdit = /* @__PURE__ */ react.forwardRef(
20
+ ({
21
+ "data-test-id": testId = "inline-edit",
22
+ layout = "horizontal",
23
+ children,
115
24
  defaultValue,
116
- onKeyDown: handleKeyDown,
117
- "aria-label": ariaLabel
118
- };
119
- const inputChildren = renderInput.props.children;
120
- const input = /* @__PURE__ */ react.cloneElement(renderInput, utils.mergeProps(renderInput.props, inputChildren ? {} : inputProps), inputChildren && react.Children.map(inputChildren, (child) => child.type === form.TextField || child.type === form.TextArea ? /* @__PURE__ */ react.cloneElement(child, utils.mergeProps(child.props, inputProps)) : child));
121
- return isEditing ? /* @__PURE__ */ jsxRuntime.jsxs("div", {
122
- ...rest,
123
- className: classix.cx(container, inline({
124
- layout
125
- }), className),
126
- "data-test-id": testId,
127
- ...focusWithinProps,
128
- children: [input, /* @__PURE__ */ jsxRuntime.jsxs(button$1.ButtonGroup, {
129
- spacing: "compact",
130
- children: [/* @__PURE__ */ jsxRuntime.jsx(button$1.IconButton, {
131
- kind: "primary",
132
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, {
133
- name: "check"
134
- }),
135
- "aria-label": confirmButtonLabel,
136
- onClick: handleConfirm
137
- }), /* @__PURE__ */ jsxRuntime.jsx(button$1.IconButton, {
138
- kind: "default",
139
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, {
140
- name: "cancel"
141
- }),
142
- "aria-label": cancelButtonLabel,
143
- className: cancelButton,
144
- onClick: handleCancel
145
- })]
146
- })]
147
- }) : /* @__PURE__ */ jsxRuntime.jsx("div", {
148
- ...rest,
149
- className: classix.cx(!hideEdit && container, className),
150
- "data-test-id": testId,
151
- ...focusWithinProps,
152
- children: renderReadContent
153
- });
154
- });
25
+ onConfirm,
26
+ hideEdit = false,
27
+ renderInput = /* @__PURE__ */ jsxRuntime.jsx(form.TextField, {}),
28
+ "aria-label": ariaLabel,
29
+ isEditing: isEditingProp,
30
+ onCancel,
31
+ onEdit,
32
+ cancelButtonLabel = "cancel",
33
+ editButtonLabel = "edit",
34
+ confirmButtonLabel = "confirm",
35
+ className,
36
+ ...rest
37
+ }, ref) => {
38
+ const [isEditing, setEditing] = react.useState(isEditingProp ?? false);
39
+ const [isFocusWithin, setFocusWithin] = react.useState(false);
40
+ const inputRef = react.useRef(null);
41
+ const editRef = react.useRef(null);
42
+ const controlled = isEditingProp !== void 0;
43
+ utils.useUpdateEffect(() => {
44
+ if (controlled) {
45
+ setEditing(isEditingProp);
46
+ }
47
+ }, [isEditingProp]);
48
+ utils.useUpdateEffect(() => {
49
+ if (isFocusWithin) {
50
+ isEditing ? inputRef.current && focus.focusSafely(inputRef.current) : editRef.current && focus.focusSafely(editRef.current);
51
+ }
52
+ }, [isEditing]);
53
+ const handleEdit = () => {
54
+ !controlled && setEditing(true);
55
+ onEdit == null ? void 0 : onEdit();
56
+ };
57
+ const handleCancel = () => {
58
+ !controlled && setEditing(false);
59
+ onCancel == null ? void 0 : onCancel();
60
+ };
61
+ const handleConfirm = () => {
62
+ var _a;
63
+ onConfirm(((_a = inputRef.current) == null ? void 0 : _a.value) || "");
64
+ !controlled && setEditing(false);
65
+ };
66
+ const handleKeyDown = (event) => {
67
+ if (event.key === "Enter") {
68
+ event.preventDefault();
69
+ handleConfirm();
70
+ } else if (event.key === "Escape") {
71
+ event.preventDefault();
72
+ handleCancel();
73
+ }
74
+ };
75
+ const { focusWithinProps } = interactions.useFocusWithin({
76
+ onBlurWithin: () => isEditing && handleCancel(),
77
+ onFocusWithinChange: (isFocusWithin2) => setFocusWithin(isFocusWithin2)
78
+ });
79
+ const { buttonProps } = button.useButton(
80
+ {
81
+ "aria-label": editButtonLabel,
82
+ elementType: "span",
83
+ onPress: handleEdit
84
+ },
85
+ editRef
86
+ );
87
+ const renderReadContent = hideEdit ? /* @__PURE__ */ jsxRuntime.jsx("span", { ref: editRef, ...buttonProps, className: readButton, children }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
88
+ children,
89
+ /* @__PURE__ */ jsxRuntime.jsx(
90
+ button$1.IconButton,
91
+ {
92
+ ref: editRef,
93
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, { name: "edit" }),
94
+ "aria-label": editButtonLabel,
95
+ size: "small",
96
+ onClick: handleEdit
97
+ }
98
+ )
99
+ ] });
100
+ const inputProps = {
101
+ ref: utils.mergeRefs(inputRef, ref),
102
+ defaultValue,
103
+ onKeyDown: handleKeyDown,
104
+ "aria-label": ariaLabel
105
+ };
106
+ const inputChildren = renderInput.props.children;
107
+ const input = /* @__PURE__ */ react.cloneElement(
108
+ renderInput,
109
+ utils.mergeProps(renderInput.props, inputChildren ? {} : inputProps),
110
+ inputChildren && react.Children.map(
111
+ inputChildren,
112
+ (child) => child.type === form.TextField || child.type === form.TextArea ? /* @__PURE__ */ react.cloneElement(child, utils.mergeProps(child.props, inputProps)) : child
113
+ )
114
+ );
115
+ return isEditing ? /* @__PURE__ */ jsxRuntime.jsxs(
116
+ "div",
117
+ {
118
+ ...rest,
119
+ className: classix.cx(container, inline({ layout }), className),
120
+ "data-test-id": testId,
121
+ ...focusWithinProps,
122
+ children: [
123
+ input,
124
+ /* @__PURE__ */ jsxRuntime.jsxs(button$1.ButtonGroup, { spacing: "compact", children: [
125
+ /* @__PURE__ */ jsxRuntime.jsx(
126
+ button$1.IconButton,
127
+ {
128
+ kind: "primary",
129
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, { name: "check" }),
130
+ "aria-label": confirmButtonLabel,
131
+ onClick: handleConfirm
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsxRuntime.jsx(
135
+ button$1.IconButton,
136
+ {
137
+ kind: "default",
138
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, { name: "cancel" }),
139
+ "aria-label": cancelButtonLabel,
140
+ className: cancelButton,
141
+ onClick: handleCancel
142
+ }
143
+ )
144
+ ] })
145
+ ]
146
+ }
147
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
148
+ "div",
149
+ {
150
+ ...rest,
151
+ className: classix.cx(!hideEdit && container, className),
152
+ "data-test-id": testId,
153
+ ...focusWithinProps,
154
+ children: renderReadContent
155
+ }
156
+ );
157
+ }
158
+ );
155
159
  InlineEdit.displayName = "InlineEdit";
156
160
  exports.InlineEdit = InlineEdit;
157
161
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/InlineEdit.tsx"],"sourcesContent":["import type { InlineVariants } from './styles/InlineEdit.css';\nimport type { IconFieldProps, TextAreaProps, TextFieldProps } from '@launchpad-ui/form';\nimport type { ComponentProps, KeyboardEventHandler, ReactElement } from 'react';\n\nimport { ButtonGroup, IconButton } from '@launchpad-ui/button';\nimport { TextField, TextArea } from '@launchpad-ui/form';\nimport { Icon } from '@launchpad-ui/icons';\nimport { useButton } from '@react-aria/button';\nimport { focusSafely } from '@react-aria/focus';\nimport { useFocusWithin } from '@react-aria/interactions';\nimport { mergeProps, mergeRefs, useUpdateEffect } from '@react-aria/utils';\nimport { cx } from 'classix';\nimport { Children, cloneElement, forwardRef, useRef, useState } from 'react';\n\nimport { container, cancelButton, inline, readButton } from './styles/InlineEdit.css';\n\ntype InlineEditProps = ComponentProps<'div'> &\n InlineVariants &\n Pick<ComponentProps<'input'>, 'defaultValue'> & {\n 'data-test-id'?: string;\n onConfirm: (value: string) => void;\n hideEdit?: boolean;\n renderInput?: ReactElement<IconFieldProps | TextFieldProps | TextAreaProps>;\n isEditing?: boolean;\n onCancel?: () => void;\n onEdit?: () => void;\n cancelButtonLabel?: string;\n editButtonLabel?: string;\n confirmButtonLabel?: string;\n };\n\nconst InlineEdit = forwardRef<HTMLInputElement, InlineEditProps>(\n (\n {\n 'data-test-id': testId = 'inline-edit',\n layout = 'horizontal',\n children,\n defaultValue,\n onConfirm,\n hideEdit = false,\n renderInput = <TextField />,\n 'aria-label': ariaLabel,\n isEditing: isEditingProp,\n onCancel,\n onEdit,\n cancelButtonLabel = 'cancel',\n editButtonLabel = 'edit',\n confirmButtonLabel = 'confirm',\n className,\n ...rest\n },\n ref\n ) => {\n const [isEditing, setEditing] = useState(isEditingProp ?? false);\n const [isFocusWithin, setFocusWithin] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const editRef = useRef<HTMLButtonElement>(null);\n const controlled = isEditingProp !== undefined;\n\n useUpdateEffect(() => {\n if (controlled) {\n setEditing(isEditingProp);\n }\n }, [isEditingProp]);\n\n useUpdateEffect(() => {\n if (isFocusWithin) {\n isEditing\n ? inputRef.current && focusSafely(inputRef.current)\n : editRef.current && focusSafely(editRef.current);\n }\n }, [isEditing]);\n\n const handleEdit = () => {\n !controlled && setEditing(true);\n onEdit?.();\n };\n\n const handleCancel = () => {\n !controlled && setEditing(false);\n onCancel?.();\n };\n\n const handleConfirm = () => {\n onConfirm(inputRef.current?.value || '');\n !controlled && setEditing(false);\n };\n\n const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n handleConfirm();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n handleCancel();\n }\n };\n\n const { focusWithinProps } = useFocusWithin({\n onBlurWithin: () => isEditing && handleCancel(),\n onFocusWithinChange: (isFocusWithin) => setFocusWithin(isFocusWithin),\n });\n\n const { buttonProps } = useButton(\n {\n 'aria-label': editButtonLabel,\n elementType: 'span',\n onPress: handleEdit,\n },\n editRef\n );\n\n const renderReadContent = hideEdit ? (\n <span ref={editRef} {...buttonProps} className={readButton}>\n {children}\n </span>\n ) : (\n <>\n {children}\n <IconButton\n ref={editRef}\n icon={<Icon name=\"edit\" />}\n aria-label={editButtonLabel}\n size=\"small\"\n onClick={handleEdit}\n />\n </>\n );\n\n const inputProps = {\n ref: mergeRefs(inputRef, ref),\n defaultValue,\n onKeyDown: handleKeyDown,\n 'aria-label': ariaLabel,\n };\n\n const inputChildren = renderInput.props.children;\n\n const input = cloneElement(\n renderInput,\n mergeProps(renderInput.props, inputChildren ? {} : inputProps),\n inputChildren &&\n Children.map(inputChildren, (child) =>\n child.type === TextField || child.type === TextArea\n ? cloneElement(child, mergeProps(child.props, inputProps))\n : child\n )\n );\n\n return isEditing ? (\n <div\n {...rest}\n className={cx(container, inline({ layout }), className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {input}\n <ButtonGroup spacing=\"compact\">\n <IconButton\n kind=\"primary\"\n icon={<Icon name=\"check\" />}\n aria-label={confirmButtonLabel}\n onClick={handleConfirm}\n />\n <IconButton\n kind=\"default\"\n icon={<Icon name=\"cancel\" />}\n aria-label={cancelButtonLabel}\n className={cancelButton}\n onClick={handleCancel}\n />\n </ButtonGroup>\n </div>\n ) : (\n <div\n {...rest}\n className={cx(!hideEdit && container, className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {renderReadContent}\n </div>\n );\n }\n);\n\nInlineEdit.displayName = 'InlineEdit';\n\nexport { InlineEdit };\nexport type { InlineEditProps };\n"],"names":["forwardRef","jsx","TextField","useState","useRef","useUpdateEffect","focusSafely","useFocusWithin","useButton","jsxs","Fragment","IconButton","Icon","mergeRefs","mergeProps","Children","TextArea","cloneElement","cx","ButtonGroup"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/InlineEdit.tsx"],"sourcesContent":["import type { InlineVariants } from './styles/InlineEdit.css';\nimport type { IconFieldProps, TextAreaProps, TextFieldProps } from '@launchpad-ui/form';\nimport type { ComponentProps, KeyboardEventHandler, ReactElement } from 'react';\n\nimport { ButtonGroup, IconButton } from '@launchpad-ui/button';\nimport { TextField, TextArea } from '@launchpad-ui/form';\nimport { Icon } from '@launchpad-ui/icons';\nimport { useButton } from '@react-aria/button';\nimport { focusSafely } from '@react-aria/focus';\nimport { useFocusWithin } from '@react-aria/interactions';\nimport { mergeProps, mergeRefs, useUpdateEffect } from '@react-aria/utils';\nimport { cx } from 'classix';\nimport { Children, cloneElement, forwardRef, useRef, useState } from 'react';\n\nimport { container, cancelButton, inline, readButton } from './styles/InlineEdit.css';\n\ntype InlineEditProps = ComponentProps<'div'> &\n InlineVariants &\n Pick<ComponentProps<'input'>, 'defaultValue'> & {\n 'data-test-id'?: string;\n onConfirm: (value: string) => void;\n hideEdit?: boolean;\n renderInput?: ReactElement<IconFieldProps | TextFieldProps | TextAreaProps>;\n isEditing?: boolean;\n onCancel?: () => void;\n onEdit?: () => void;\n cancelButtonLabel?: string;\n editButtonLabel?: string;\n confirmButtonLabel?: string;\n };\n\nconst InlineEdit = forwardRef<HTMLInputElement, InlineEditProps>(\n (\n {\n 'data-test-id': testId = 'inline-edit',\n layout = 'horizontal',\n children,\n defaultValue,\n onConfirm,\n hideEdit = false,\n renderInput = <TextField />,\n 'aria-label': ariaLabel,\n isEditing: isEditingProp,\n onCancel,\n onEdit,\n cancelButtonLabel = 'cancel',\n editButtonLabel = 'edit',\n confirmButtonLabel = 'confirm',\n className,\n ...rest\n },\n ref\n ) => {\n const [isEditing, setEditing] = useState(isEditingProp ?? false);\n const [isFocusWithin, setFocusWithin] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const editRef = useRef<HTMLButtonElement>(null);\n const controlled = isEditingProp !== undefined;\n\n useUpdateEffect(() => {\n if (controlled) {\n setEditing(isEditingProp);\n }\n }, [isEditingProp]);\n\n useUpdateEffect(() => {\n if (isFocusWithin) {\n isEditing\n ? inputRef.current && focusSafely(inputRef.current)\n : editRef.current && focusSafely(editRef.current);\n }\n }, [isEditing]);\n\n const handleEdit = () => {\n !controlled && setEditing(true);\n onEdit?.();\n };\n\n const handleCancel = () => {\n !controlled && setEditing(false);\n onCancel?.();\n };\n\n const handleConfirm = () => {\n onConfirm(inputRef.current?.value || '');\n !controlled && setEditing(false);\n };\n\n const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n handleConfirm();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n handleCancel();\n }\n };\n\n const { focusWithinProps } = useFocusWithin({\n onBlurWithin: () => isEditing && handleCancel(),\n onFocusWithinChange: (isFocusWithin) => setFocusWithin(isFocusWithin),\n });\n\n const { buttonProps } = useButton(\n {\n 'aria-label': editButtonLabel,\n elementType: 'span',\n onPress: handleEdit,\n },\n editRef\n );\n\n const renderReadContent = hideEdit ? (\n <span ref={editRef} {...buttonProps} className={readButton}>\n {children}\n </span>\n ) : (\n <>\n {children}\n <IconButton\n ref={editRef}\n icon={<Icon name=\"edit\" />}\n aria-label={editButtonLabel}\n size=\"small\"\n onClick={handleEdit}\n />\n </>\n );\n\n const inputProps = {\n ref: mergeRefs(inputRef, ref),\n defaultValue,\n onKeyDown: handleKeyDown,\n 'aria-label': ariaLabel,\n };\n\n const inputChildren = renderInput.props.children;\n\n const input = cloneElement(\n renderInput,\n mergeProps(renderInput.props, inputChildren ? {} : inputProps),\n inputChildren &&\n Children.map(inputChildren, (child) =>\n child.type === TextField || child.type === TextArea\n ? cloneElement(child, mergeProps(child.props, inputProps))\n : child\n )\n );\n\n return isEditing ? (\n <div\n {...rest}\n className={cx(container, inline({ layout }), className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {input}\n <ButtonGroup spacing=\"compact\">\n <IconButton\n kind=\"primary\"\n icon={<Icon name=\"check\" />}\n aria-label={confirmButtonLabel}\n onClick={handleConfirm}\n />\n <IconButton\n kind=\"default\"\n icon={<Icon name=\"cancel\" />}\n aria-label={cancelButtonLabel}\n className={cancelButton}\n onClick={handleCancel}\n />\n </ButtonGroup>\n </div>\n ) : (\n <div\n {...rest}\n className={cx(!hideEdit && container, className)}\n data-test-id={testId}\n {...focusWithinProps}\n >\n {renderReadContent}\n </div>\n );\n }\n);\n\nInlineEdit.displayName = 'InlineEdit';\n\nexport { InlineEdit };\nexport type { InlineEditProps };\n"],"names":["forwardRef","TextField","useState","useRef","useUpdateEffect","focusSafely","useFocusWithin","isFocusWithin","useButton","jsx","jsxs","Fragment","IconButton","Icon","mergeRefs","cloneElement","mergeProps","Children","TextArea","cx","ButtonGroup"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchpad-ui/inline-edit",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "status": "alpha",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -26,14 +26,14 @@
26
26
  },
27
27
  "source": "src/index.ts",
28
28
  "dependencies": {
29
- "@react-aria/button": "3.9.0",
30
- "@react-aria/focus": "3.15.0",
31
- "@react-aria/interactions": "3.20.0",
32
- "@react-aria/utils": "3.22.0",
29
+ "@react-aria/button": "3.9.1",
30
+ "@react-aria/focus": "3.16.0",
31
+ "@react-aria/interactions": "3.20.1",
32
+ "@react-aria/utils": "3.23.0",
33
33
  "@vanilla-extract/recipes": "^0.5.0",
34
34
  "classix": "2.1.17",
35
35
  "@launchpad-ui/button": "~0.11.9",
36
- "@launchpad-ui/form": "~0.10.10",
36
+ "@launchpad-ui/form": "~0.10.11",
37
37
  "@launchpad-ui/icons": "~0.14.9",
38
38
  "@launchpad-ui/tokens": "~0.9.2",
39
39
  "@launchpad-ui/vars": "~0.2.9"
@@ -48,7 +48,7 @@
48
48
  "react-dom": "18.2.0"
49
49
  },
50
50
  "scripts": {
51
- "build": "vite build -c ../../vite.config.ts && tsc --project tsconfig.build.json",
51
+ "build": "vite build -c ../../vite.config.mts && tsc --project tsconfig.build.json",
52
52
  "clean": "rm -rf dist",
53
53
  "lint": "eslint '**/*.{ts,tsx,js}'",
54
54
  "test": "vitest run --coverage"