myoperator-ui 0.0.94 → 0.0.95
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.js +151 -147
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3809,10 +3809,10 @@ export { PageHeader, pageHeaderVariants };
|
|
|
3809
3809
|
files: [
|
|
3810
3810
|
{
|
|
3811
3811
|
name: "event-selector.tsx",
|
|
3812
|
-
content: prefixTailwindClasses(`import * as React from "react"
|
|
3813
|
-
import { cn } from "../../../lib/utils"
|
|
3814
|
-
import { EventGroupComponent } from "./event-group"
|
|
3815
|
-
import type { EventSelectorProps, EventCategory, EventGroup } from "./types"
|
|
3812
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
3813
|
+
import { cn } from "../../../lib/utils";
|
|
3814
|
+
import { EventGroupComponent } from "./event-group";
|
|
3815
|
+
import type { EventSelectorProps, EventCategory, EventGroup } from "./types";
|
|
3816
3816
|
|
|
3817
3817
|
/**
|
|
3818
3818
|
* EventSelector - A component for selecting webhook events
|
|
@@ -3837,7 +3837,10 @@ import type { EventSelectorProps, EventCategory, EventGroup } from "./types"
|
|
|
3837
3837
|
* />
|
|
3838
3838
|
* \`\`\`
|
|
3839
3839
|
*/
|
|
3840
|
-
export const EventSelector = React.forwardRef<
|
|
3840
|
+
export const EventSelector = React.forwardRef<
|
|
3841
|
+
HTMLDivElement,
|
|
3842
|
+
EventSelectorProps
|
|
3843
|
+
>(
|
|
3841
3844
|
(
|
|
3842
3845
|
{
|
|
3843
3846
|
events,
|
|
@@ -3858,35 +3861,35 @@ export const EventSelector = React.forwardRef<HTMLDivElement, EventSelectorProps
|
|
|
3858
3861
|
// Controlled vs uncontrolled state
|
|
3859
3862
|
const [internalSelected, setInternalSelected] = React.useState<string[]>(
|
|
3860
3863
|
defaultSelectedEvents
|
|
3861
|
-
)
|
|
3864
|
+
);
|
|
3862
3865
|
|
|
3863
|
-
const isControlled = controlledSelected !== undefined
|
|
3864
|
-
const selectedEvents = isControlled ? controlledSelected : internalSelected
|
|
3866
|
+
const isControlled = controlledSelected !== undefined;
|
|
3867
|
+
const selectedEvents = isControlled ? controlledSelected : internalSelected;
|
|
3865
3868
|
|
|
3866
3869
|
const handleSelectionChange = React.useCallback(
|
|
3867
3870
|
(newSelection: string[]) => {
|
|
3868
3871
|
if (!isControlled) {
|
|
3869
|
-
setInternalSelected(newSelection)
|
|
3872
|
+
setInternalSelected(newSelection);
|
|
3870
3873
|
}
|
|
3871
|
-
onSelectionChange?.(newSelection)
|
|
3874
|
+
onSelectionChange?.(newSelection);
|
|
3872
3875
|
},
|
|
3873
3876
|
[isControlled, onSelectionChange]
|
|
3874
|
-
)
|
|
3877
|
+
);
|
|
3875
3878
|
|
|
3876
3879
|
// Get events for a specific group
|
|
3877
3880
|
const getEventsForGroup = (groupId: string) => {
|
|
3878
|
-
return events.filter((event) => event.group === groupId)
|
|
3879
|
-
}
|
|
3881
|
+
return events.filter((event) => event.group === groupId);
|
|
3882
|
+
};
|
|
3880
3883
|
|
|
3881
3884
|
// Get groups for a specific category
|
|
3882
3885
|
const getGroupsForCategory = (category: EventCategory): EventGroup[] => {
|
|
3883
3886
|
return category.groups
|
|
3884
3887
|
.map((groupId) => groups.find((g) => g.id === groupId))
|
|
3885
|
-
.filter((g): g is EventGroup => g !== undefined)
|
|
3886
|
-
}
|
|
3888
|
+
.filter((g): g is EventGroup => g !== undefined);
|
|
3889
|
+
};
|
|
3887
3890
|
|
|
3888
3891
|
// Calculate total selected count
|
|
3889
|
-
const totalSelected = selectedEvents.length
|
|
3892
|
+
const totalSelected = selectedEvents.length;
|
|
3890
3893
|
|
|
3891
3894
|
// Render groups without categories
|
|
3892
3895
|
const renderGroups = (groupsToRender: EventGroup[]) => {
|
|
@@ -3900,32 +3903,36 @@ export const EventSelector = React.forwardRef<HTMLDivElement, EventSelectorProps
|
|
|
3900
3903
|
emptyGroupMessage={emptyGroupMessage}
|
|
3901
3904
|
renderEmptyGroup={renderEmptyGroup}
|
|
3902
3905
|
/>
|
|
3903
|
-
))
|
|
3904
|
-
}
|
|
3906
|
+
));
|
|
3907
|
+
};
|
|
3905
3908
|
|
|
3906
3909
|
// Render categories with nested groups
|
|
3907
3910
|
const renderCategories = () => {
|
|
3908
3911
|
// Ensure categories is an array before using array methods
|
|
3909
|
-
if (
|
|
3910
|
-
|
|
3912
|
+
if (
|
|
3913
|
+
!categories ||
|
|
3914
|
+
!Array.isArray(categories) ||
|
|
3915
|
+
categories.length === 0
|
|
3916
|
+
) {
|
|
3917
|
+
return renderGroups(groups);
|
|
3911
3918
|
}
|
|
3912
3919
|
|
|
3913
3920
|
// Get groups that belong to categories
|
|
3914
|
-
const groupsInCategories = new Set(categories.flatMap((c) => c.groups))
|
|
3921
|
+
const groupsInCategories = new Set(categories.flatMap((c) => c.groups));
|
|
3915
3922
|
|
|
3916
3923
|
// Get orphan groups (not in any category)
|
|
3917
|
-
const orphanGroups = groups.filter((g) => !groupsInCategories.has(g.id))
|
|
3924
|
+
const orphanGroups = groups.filter((g) => !groupsInCategories.has(g.id));
|
|
3918
3925
|
|
|
3919
3926
|
return (
|
|
3920
3927
|
<>
|
|
3921
3928
|
{categories.map((category) => {
|
|
3922
|
-
const categoryGroups = getGroupsForCategory(category)
|
|
3929
|
+
const categoryGroups = getGroupsForCategory(category);
|
|
3923
3930
|
const categoryEventIds = categoryGroups.flatMap((g) =>
|
|
3924
3931
|
getEventsForGroup(g.id).map((e) => e.id)
|
|
3925
|
-
)
|
|
3932
|
+
);
|
|
3926
3933
|
const selectedInCategory = categoryEventIds.filter((id) =>
|
|
3927
3934
|
selectedEvents.includes(id)
|
|
3928
|
-
)
|
|
3935
|
+
);
|
|
3929
3936
|
|
|
3930
3937
|
return (
|
|
3931
3938
|
<div
|
|
@@ -3955,24 +3962,22 @@ export const EventSelector = React.forwardRef<HTMLDivElement, EventSelectorProps
|
|
|
3955
3962
|
{renderGroups(categoryGroups)}
|
|
3956
3963
|
</div>
|
|
3957
3964
|
</div>
|
|
3958
|
-
)
|
|
3965
|
+
);
|
|
3959
3966
|
})}
|
|
3960
3967
|
{/* Render orphan groups outside categories */}
|
|
3961
3968
|
{orphanGroups.length > 0 && renderGroups(orphanGroups)}
|
|
3962
3969
|
</>
|
|
3963
|
-
)
|
|
3964
|
-
}
|
|
3970
|
+
);
|
|
3971
|
+
};
|
|
3965
3972
|
|
|
3966
3973
|
return (
|
|
3967
|
-
<div
|
|
3968
|
-
ref={ref}
|
|
3969
|
-
className={cn("w-full", className)}
|
|
3970
|
-
{...props}
|
|
3971
|
-
>
|
|
3974
|
+
<div ref={ref} className={cn("w-full", className)} {...props}>
|
|
3972
3975
|
{/* Header */}
|
|
3973
3976
|
<div className="flex items-start justify-between mb-4">
|
|
3974
3977
|
<div>
|
|
3975
|
-
<h3 className="m-0 text-base font-semibold text-[#333333]">
|
|
3978
|
+
<h3 className="m-0 text-base font-semibold text-[#333333]">
|
|
3979
|
+
{title}
|
|
3980
|
+
</h3>
|
|
3976
3981
|
{description && (
|
|
3977
3982
|
<p className="m-0 text-sm text-[#6B7280] mt-1">{description}</p>
|
|
3978
3983
|
)}
|
|
@@ -3987,25 +3992,25 @@ export const EventSelector = React.forwardRef<HTMLDivElement, EventSelectorProps
|
|
|
3987
3992
|
{renderCategories()}
|
|
3988
3993
|
</div>
|
|
3989
3994
|
</div>
|
|
3990
|
-
)
|
|
3995
|
+
);
|
|
3991
3996
|
}
|
|
3992
|
-
)
|
|
3993
|
-
EventSelector.displayName = "EventSelector"
|
|
3997
|
+
);
|
|
3998
|
+
EventSelector.displayName = "EventSelector";
|
|
3994
3999
|
`, prefix)
|
|
3995
4000
|
},
|
|
3996
4001
|
{
|
|
3997
4002
|
name: "event-group.tsx",
|
|
3998
|
-
content: prefixTailwindClasses(`import * as React from "react"
|
|
3999
|
-
import { cn } from "../../../lib/utils"
|
|
4000
|
-
import { Checkbox, type CheckedState } from "../checkbox"
|
|
4003
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
4004
|
+
import { cn } from "../../../lib/utils";
|
|
4005
|
+
import { Checkbox, type CheckedState } from "../checkbox";
|
|
4001
4006
|
import {
|
|
4002
4007
|
Accordion,
|
|
4003
4008
|
AccordionItem,
|
|
4004
4009
|
AccordionTrigger,
|
|
4005
4010
|
AccordionContent,
|
|
4006
|
-
} from "../accordion"
|
|
4007
|
-
import { EventItemComponent } from "./event-item"
|
|
4008
|
-
import type { EventGroupComponentProps } from "./types"
|
|
4011
|
+
} from "../accordion";
|
|
4012
|
+
import { EventItemComponent } from "./event-item";
|
|
4013
|
+
import type { EventGroupComponentProps } from "./types";
|
|
4009
4014
|
|
|
4010
4015
|
/**
|
|
4011
4016
|
* Event group with accordion section and group-level checkbox
|
|
@@ -4028,58 +4033,60 @@ export const EventGroupComponent = React.forwardRef<
|
|
|
4028
4033
|
ref
|
|
4029
4034
|
) => {
|
|
4030
4035
|
// Calculate selection state for this group
|
|
4031
|
-
const groupEventIds = events.map((e) => e.id)
|
|
4036
|
+
const groupEventIds = events.map((e) => e.id);
|
|
4032
4037
|
const selectedInGroup = groupEventIds.filter((id) =>
|
|
4033
4038
|
selectedEvents.includes(id)
|
|
4034
|
-
)
|
|
4035
|
-
const allSelected =
|
|
4036
|
-
|
|
4039
|
+
);
|
|
4040
|
+
const allSelected =
|
|
4041
|
+
groupEventIds.length > 0 &&
|
|
4042
|
+
selectedInGroup.length === groupEventIds.length;
|
|
4043
|
+
const someSelected =
|
|
4044
|
+
selectedInGroup.length > 0 &&
|
|
4045
|
+
selectedInGroup.length < groupEventIds.length;
|
|
4037
4046
|
|
|
4038
4047
|
const checkboxState: CheckedState = allSelected
|
|
4039
4048
|
? true
|
|
4040
4049
|
: someSelected
|
|
4041
|
-
|
|
4042
|
-
|
|
4050
|
+
? "indeterminate"
|
|
4051
|
+
: false;
|
|
4043
4052
|
|
|
4044
|
-
const selectedCount = selectedInGroup.length
|
|
4053
|
+
const selectedCount = selectedInGroup.length;
|
|
4045
4054
|
|
|
4046
4055
|
// Handle group checkbox click
|
|
4047
4056
|
const handleGroupCheckbox = () => {
|
|
4048
4057
|
if (allSelected) {
|
|
4049
4058
|
// Deselect all events in this group
|
|
4050
|
-
onSelectionChange(
|
|
4059
|
+
onSelectionChange(
|
|
4060
|
+
selectedEvents.filter((id) => !groupEventIds.includes(id))
|
|
4061
|
+
);
|
|
4051
4062
|
} else {
|
|
4052
4063
|
// Select all events in this group
|
|
4053
|
-
const newSelection = [...selectedEvents]
|
|
4064
|
+
const newSelection = [...selectedEvents];
|
|
4054
4065
|
groupEventIds.forEach((id) => {
|
|
4055
4066
|
if (!newSelection.includes(id)) {
|
|
4056
|
-
newSelection.push(id)
|
|
4067
|
+
newSelection.push(id);
|
|
4057
4068
|
}
|
|
4058
|
-
})
|
|
4059
|
-
onSelectionChange(newSelection)
|
|
4069
|
+
});
|
|
4070
|
+
onSelectionChange(newSelection);
|
|
4060
4071
|
}
|
|
4061
|
-
}
|
|
4072
|
+
};
|
|
4062
4073
|
|
|
4063
4074
|
// Handle individual event selection
|
|
4064
4075
|
const handleEventSelection = (eventId: string, selected: boolean) => {
|
|
4065
4076
|
if (selected) {
|
|
4066
|
-
onSelectionChange([...selectedEvents, eventId])
|
|
4077
|
+
onSelectionChange([...selectedEvents, eventId]);
|
|
4067
4078
|
} else {
|
|
4068
|
-
onSelectionChange(selectedEvents.filter((id) => id !== eventId))
|
|
4079
|
+
onSelectionChange(selectedEvents.filter((id) => id !== eventId));
|
|
4069
4080
|
}
|
|
4070
|
-
}
|
|
4081
|
+
};
|
|
4071
4082
|
|
|
4072
4083
|
// Single event in group: render as flat item (no accordion)
|
|
4073
4084
|
if (events.length === 1) {
|
|
4074
|
-
const event = events[0]
|
|
4075
|
-
const isSelected = selectedEvents.includes(event.id)
|
|
4085
|
+
const event = events[0];
|
|
4086
|
+
const isSelected = selectedEvents.includes(event.id);
|
|
4076
4087
|
|
|
4077
4088
|
return (
|
|
4078
|
-
<div
|
|
4079
|
-
ref={ref}
|
|
4080
|
-
className={cn("bg-white p-4", className)}
|
|
4081
|
-
{...props}
|
|
4082
|
-
>
|
|
4089
|
+
<div ref={ref} className={cn("bg-white p-4", className)} {...props}>
|
|
4083
4090
|
<div className="flex items-start gap-3">
|
|
4084
4091
|
<Checkbox
|
|
4085
4092
|
checked={isSelected}
|
|
@@ -4091,20 +4098,18 @@ export const EventGroupComponent = React.forwardRef<
|
|
|
4091
4098
|
/>
|
|
4092
4099
|
<div className="flex-1 min-w-0">
|
|
4093
4100
|
<span className="font-medium text-[#333333]">{event.name}</span>
|
|
4094
|
-
<p className="m-0 text-sm text-[#6B7280] mt-0.5">
|
|
4101
|
+
<p className="m-0 text-sm text-[#6B7280] mt-0.5">
|
|
4102
|
+
{event.description}
|
|
4103
|
+
</p>
|
|
4095
4104
|
</div>
|
|
4096
4105
|
</div>
|
|
4097
4106
|
</div>
|
|
4098
|
-
)
|
|
4107
|
+
);
|
|
4099
4108
|
}
|
|
4100
4109
|
|
|
4101
4110
|
// Multiple events: render as collapsible accordion
|
|
4102
4111
|
return (
|
|
4103
|
-
<div
|
|
4104
|
-
ref={ref}
|
|
4105
|
-
className={cn("bg-white", className)}
|
|
4106
|
-
{...props}
|
|
4107
|
-
>
|
|
4112
|
+
<div ref={ref} className={cn("bg-white", className)} {...props}>
|
|
4108
4113
|
<Accordion type="multiple">
|
|
4109
4114
|
<AccordionItem value={group.id}>
|
|
4110
4115
|
<AccordionTrigger
|
|
@@ -4152,9 +4157,7 @@ export const EventGroupComponent = React.forwardRef<
|
|
|
4152
4157
|
/>
|
|
4153
4158
|
))
|
|
4154
4159
|
) : renderEmptyGroup ? (
|
|
4155
|
-
<div className="py-4 px-8">
|
|
4156
|
-
{renderEmptyGroup(group)}
|
|
4157
|
-
</div>
|
|
4160
|
+
<div className="py-4 px-8">{renderEmptyGroup(group)}</div>
|
|
4158
4161
|
) : (
|
|
4159
4162
|
<div className="py-4 px-8 text-sm text-[#6B7280] italic">
|
|
4160
4163
|
{emptyGroupMessage}
|
|
@@ -4165,18 +4168,18 @@ export const EventGroupComponent = React.forwardRef<
|
|
|
4165
4168
|
</AccordionItem>
|
|
4166
4169
|
</Accordion>
|
|
4167
4170
|
</div>
|
|
4168
|
-
)
|
|
4171
|
+
);
|
|
4169
4172
|
}
|
|
4170
|
-
)
|
|
4171
|
-
EventGroupComponent.displayName = "EventGroupComponent"
|
|
4173
|
+
);
|
|
4174
|
+
EventGroupComponent.displayName = "EventGroupComponent";
|
|
4172
4175
|
`, prefix)
|
|
4173
4176
|
},
|
|
4174
4177
|
{
|
|
4175
4178
|
name: "event-item.tsx",
|
|
4176
|
-
content: prefixTailwindClasses(`import * as React from "react"
|
|
4177
|
-
import { cn } from "../../../lib/utils"
|
|
4178
|
-
import { Checkbox } from "../checkbox"
|
|
4179
|
-
import type { EventItemComponentProps } from "./types"
|
|
4179
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
4180
|
+
import { cn } from "../../../lib/utils";
|
|
4181
|
+
import { Checkbox } from "../checkbox";
|
|
4182
|
+
import type { EventItemComponentProps } from "./types";
|
|
4180
4183
|
|
|
4181
4184
|
/**
|
|
4182
4185
|
* Individual event item with checkbox
|
|
@@ -4188,10 +4191,7 @@ export const EventItemComponent = React.forwardRef<
|
|
|
4188
4191
|
return (
|
|
4189
4192
|
<div
|
|
4190
4193
|
ref={ref}
|
|
4191
|
-
className={cn(
|
|
4192
|
-
"flex items-start gap-3 py-2 pl-8 pr-4",
|
|
4193
|
-
className
|
|
4194
|
-
)}
|
|
4194
|
+
className={cn("flex items-start gap-3 py-2 pl-8 pr-4", className)}
|
|
4195
4195
|
{...props}
|
|
4196
4196
|
>
|
|
4197
4197
|
<Checkbox
|
|
@@ -4206,9 +4206,9 @@ export const EventItemComponent = React.forwardRef<
|
|
|
4206
4206
|
</div>
|
|
4207
4207
|
</div>
|
|
4208
4208
|
</div>
|
|
4209
|
-
)
|
|
4210
|
-
})
|
|
4211
|
-
EventItemComponent.displayName = "EventItemComponent"
|
|
4209
|
+
);
|
|
4210
|
+
});
|
|
4211
|
+
EventItemComponent.displayName = "EventItemComponent";
|
|
4212
4212
|
`, prefix)
|
|
4213
4213
|
},
|
|
4214
4214
|
{
|
|
@@ -4345,16 +4345,16 @@ export interface EventItemComponentProps {
|
|
|
4345
4345
|
files: [
|
|
4346
4346
|
{
|
|
4347
4347
|
name: "key-value-input.tsx",
|
|
4348
|
-
content: prefixTailwindClasses(`import * as React from "react"
|
|
4349
|
-
import { Plus } from "lucide-react"
|
|
4350
|
-
import { cn } from "../../../lib/utils"
|
|
4351
|
-
import { Button } from "../button"
|
|
4352
|
-
import { KeyValueRow } from "./key-value-row"
|
|
4353
|
-
import type { KeyValueInputProps, KeyValuePair } from "./types"
|
|
4348
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
4349
|
+
import { Plus } from "lucide-react";
|
|
4350
|
+
import { cn } from "../../../lib/utils";
|
|
4351
|
+
import { Button } from "../button";
|
|
4352
|
+
import { KeyValueRow } from "./key-value-row";
|
|
4353
|
+
import type { KeyValueInputProps, KeyValuePair } from "./types";
|
|
4354
4354
|
|
|
4355
4355
|
// Helper to generate unique IDs
|
|
4356
4356
|
const generateId = () =>
|
|
4357
|
-
\`kv-\${Date.now()}-\${Math.random().toString(36).substr(2, 9)}
|
|
4357
|
+
\`kv-\${Date.now()}-\${Math.random().toString(36).substr(2, 9)}\`;
|
|
4358
4358
|
|
|
4359
4359
|
/**
|
|
4360
4360
|
* KeyValueInput - A component for managing key-value pairs
|
|
@@ -4403,88 +4403,92 @@ export const KeyValueInput = React.forwardRef<
|
|
|
4403
4403
|
) => {
|
|
4404
4404
|
// Controlled vs uncontrolled state
|
|
4405
4405
|
const [internalPairs, setInternalPairs] =
|
|
4406
|
-
React.useState<KeyValuePair[]>(defaultValue)
|
|
4406
|
+
React.useState<KeyValuePair[]>(defaultValue);
|
|
4407
4407
|
|
|
4408
|
-
const isControlled = controlledValue !== undefined
|
|
4409
|
-
const pairs = isControlled ? controlledValue : internalPairs
|
|
4408
|
+
const isControlled = controlledValue !== undefined;
|
|
4409
|
+
const pairs = isControlled ? controlledValue : internalPairs;
|
|
4410
4410
|
|
|
4411
4411
|
// Track which keys have been touched for validation
|
|
4412
|
-
const [touchedKeys, setTouchedKeys] = React.useState<Set<string>>(
|
|
4412
|
+
const [touchedKeys, setTouchedKeys] = React.useState<Set<string>>(
|
|
4413
|
+
new Set()
|
|
4414
|
+
);
|
|
4413
4415
|
|
|
4414
4416
|
const handlePairsChange = React.useCallback(
|
|
4415
4417
|
(newPairs: KeyValuePair[]) => {
|
|
4416
4418
|
if (!isControlled) {
|
|
4417
|
-
setInternalPairs(newPairs)
|
|
4419
|
+
setInternalPairs(newPairs);
|
|
4418
4420
|
}
|
|
4419
|
-
onChange?.(newPairs)
|
|
4421
|
+
onChange?.(newPairs);
|
|
4420
4422
|
},
|
|
4421
4423
|
[isControlled, onChange]
|
|
4422
|
-
)
|
|
4424
|
+
);
|
|
4423
4425
|
|
|
4424
4426
|
// Check for duplicate keys (case-insensitive)
|
|
4425
4427
|
const getDuplicateKeys = React.useCallback((): Set<string> => {
|
|
4426
|
-
const keyCount = new Map<string, number>()
|
|
4428
|
+
const keyCount = new Map<string, number>();
|
|
4427
4429
|
pairs.forEach((pair) => {
|
|
4428
4430
|
if (pair.key.trim()) {
|
|
4429
|
-
const key = pair.key.toLowerCase()
|
|
4430
|
-
keyCount.set(key, (keyCount.get(key) || 0) + 1)
|
|
4431
|
+
const key = pair.key.toLowerCase();
|
|
4432
|
+
keyCount.set(key, (keyCount.get(key) || 0) + 1);
|
|
4431
4433
|
}
|
|
4432
|
-
})
|
|
4433
|
-
const duplicates = new Set<string>()
|
|
4434
|
+
});
|
|
4435
|
+
const duplicates = new Set<string>();
|
|
4434
4436
|
keyCount.forEach((count, key) => {
|
|
4435
|
-
if (count > 1) duplicates.add(key)
|
|
4436
|
-
})
|
|
4437
|
-
return duplicates
|
|
4438
|
-
}, [pairs])
|
|
4437
|
+
if (count > 1) duplicates.add(key);
|
|
4438
|
+
});
|
|
4439
|
+
return duplicates;
|
|
4440
|
+
}, [pairs]);
|
|
4439
4441
|
|
|
4440
|
-
const duplicateKeys = getDuplicateKeys()
|
|
4442
|
+
const duplicateKeys = getDuplicateKeys();
|
|
4441
4443
|
|
|
4442
4444
|
// Add new row
|
|
4443
4445
|
const handleAdd = () => {
|
|
4444
|
-
if (pairs.length >= maxItems) return
|
|
4446
|
+
if (pairs.length >= maxItems) return;
|
|
4445
4447
|
const newPair: KeyValuePair = {
|
|
4446
4448
|
id: generateId(),
|
|
4447
4449
|
key: "",
|
|
4448
4450
|
value: "",
|
|
4449
|
-
}
|
|
4450
|
-
handlePairsChange([...pairs, newPair])
|
|
4451
|
-
}
|
|
4451
|
+
};
|
|
4452
|
+
handlePairsChange([...pairs, newPair]);
|
|
4453
|
+
};
|
|
4452
4454
|
|
|
4453
4455
|
// Update key
|
|
4454
4456
|
const handleKeyChange = (id: string, key: string) => {
|
|
4455
4457
|
handlePairsChange(
|
|
4456
4458
|
pairs.map((pair) => (pair.id === id ? { ...pair, key } : pair))
|
|
4457
|
-
)
|
|
4458
|
-
setTouchedKeys((prev) => new Set(prev).add(id))
|
|
4459
|
-
}
|
|
4459
|
+
);
|
|
4460
|
+
setTouchedKeys((prev) => new Set(prev).add(id));
|
|
4461
|
+
};
|
|
4460
4462
|
|
|
4461
4463
|
// Update value
|
|
4462
4464
|
const handleValueChange = (id: string, value: string) => {
|
|
4463
4465
|
handlePairsChange(
|
|
4464
4466
|
pairs.map((pair) => (pair.id === id ? { ...pair, value } : pair))
|
|
4465
|
-
)
|
|
4466
|
-
}
|
|
4467
|
+
);
|
|
4468
|
+
};
|
|
4467
4469
|
|
|
4468
4470
|
// Delete row
|
|
4469
4471
|
const handleDelete = (id: string) => {
|
|
4470
|
-
handlePairsChange(pairs.filter((pair) => pair.id !== id))
|
|
4472
|
+
handlePairsChange(pairs.filter((pair) => pair.id !== id));
|
|
4471
4473
|
setTouchedKeys((prev) => {
|
|
4472
|
-
const next = new Set(prev)
|
|
4473
|
-
next.delete(id)
|
|
4474
|
-
return next
|
|
4475
|
-
})
|
|
4476
|
-
}
|
|
4474
|
+
const next = new Set(prev);
|
|
4475
|
+
next.delete(id);
|
|
4476
|
+
return next;
|
|
4477
|
+
});
|
|
4478
|
+
};
|
|
4477
4479
|
|
|
4478
|
-
const isAtLimit = pairs.length >= maxItems
|
|
4480
|
+
const isAtLimit = pairs.length >= maxItems;
|
|
4479
4481
|
const addButtonTitle = isAtLimit
|
|
4480
4482
|
? \`Maximum of \${maxItems} items allowed\`
|
|
4481
|
-
: undefined
|
|
4483
|
+
: undefined;
|
|
4482
4484
|
|
|
4483
4485
|
return (
|
|
4484
4486
|
<div ref={ref} className={cn("w-full", className)} {...props}>
|
|
4485
4487
|
{/* Header */}
|
|
4486
4488
|
<div className="mb-3">
|
|
4487
|
-
<h3 className="m-0 text-base font-semibold text-[#333333]">
|
|
4489
|
+
<h3 className="m-0 text-base font-semibold text-[#333333]">
|
|
4490
|
+
{title}
|
|
4491
|
+
</h3>
|
|
4488
4492
|
{description && (
|
|
4489
4493
|
<p className="m-0 text-sm text-[#6B7280] mt-1">{description}</p>
|
|
4490
4494
|
)}
|
|
@@ -4549,20 +4553,20 @@ export const KeyValueInput = React.forwardRef<
|
|
|
4549
4553
|
</p>
|
|
4550
4554
|
)}
|
|
4551
4555
|
</div>
|
|
4552
|
-
)
|
|
4556
|
+
);
|
|
4553
4557
|
}
|
|
4554
|
-
)
|
|
4555
|
-
KeyValueInput.displayName = "KeyValueInput"
|
|
4558
|
+
);
|
|
4559
|
+
KeyValueInput.displayName = "KeyValueInput";
|
|
4556
4560
|
`, prefix)
|
|
4557
4561
|
},
|
|
4558
4562
|
{
|
|
4559
4563
|
name: "key-value-row.tsx",
|
|
4560
|
-
content: prefixTailwindClasses(`import * as React from "react"
|
|
4561
|
-
import { Trash2 } from "lucide-react"
|
|
4562
|
-
import { cn } from "../../../lib/utils"
|
|
4563
|
-
import { Input } from "../input"
|
|
4564
|
-
import { Button } from "../button"
|
|
4565
|
-
import type { KeyValueRowProps } from "./types"
|
|
4564
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
4565
|
+
import { Trash2 } from "lucide-react";
|
|
4566
|
+
import { cn } from "../../../lib/utils";
|
|
4567
|
+
import { Input } from "../input";
|
|
4568
|
+
import { Button } from "../button";
|
|
4569
|
+
import type { KeyValueRowProps } from "./types";
|
|
4566
4570
|
|
|
4567
4571
|
/**
|
|
4568
4572
|
* Individual key-value pair row with inputs and delete button
|
|
@@ -4587,14 +4591,14 @@ export const KeyValueRow = React.forwardRef<
|
|
|
4587
4591
|
ref
|
|
4588
4592
|
) => {
|
|
4589
4593
|
// Determine if key input should show error state
|
|
4590
|
-
const keyHasError = isDuplicateKey || isKeyEmpty
|
|
4594
|
+
const keyHasError = isDuplicateKey || isKeyEmpty;
|
|
4591
4595
|
|
|
4592
4596
|
// Determine error message
|
|
4593
4597
|
const errorMessage = isDuplicateKey
|
|
4594
4598
|
? "Duplicate key"
|
|
4595
4599
|
: isKeyEmpty
|
|
4596
|
-
|
|
4597
|
-
|
|
4600
|
+
? "Key is required"
|
|
4601
|
+
: null;
|
|
4598
4602
|
|
|
4599
4603
|
return (
|
|
4600
4604
|
<div
|
|
@@ -4640,10 +4644,10 @@ export const KeyValueRow = React.forwardRef<
|
|
|
4640
4644
|
<Trash2 className="h-4 w-4" />
|
|
4641
4645
|
</Button>
|
|
4642
4646
|
</div>
|
|
4643
|
-
)
|
|
4647
|
+
);
|
|
4644
4648
|
}
|
|
4645
|
-
)
|
|
4646
|
-
KeyValueRow.displayName = "KeyValueRow"
|
|
4649
|
+
);
|
|
4650
|
+
KeyValueRow.displayName = "KeyValueRow";
|
|
4647
4651
|
`, prefix)
|
|
4648
4652
|
},
|
|
4649
4653
|
{
|