@bento/use-props 0.2.1 → 0.2.3

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.cjs CHANGED
@@ -1,98 +1,175 @@
1
- 'use strict';
2
-
3
- var box = require('@bento/box');
4
- var internalProps = require('@bento/internal-props');
5
- var utils = require('@react-aria/utils');
6
- var react = require('react');
7
-
8
- // src/index.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _bento_box = require("@bento/box");
3
+ let _bento_internal_props = require("@bento/internal-props");
4
+ let _react_aria_utils = require("@react-aria/utils");
5
+ let react = require("react");
6
+ //#region src/index.ts
7
+ /**
8
+ * Checks if the given string is an event listener name. An event listener name
9
+ * is defined as a string that starts with "on" followed by an uppercase letter.
10
+ *
11
+ * @param name - The string to check.
12
+ * @returns `true` if the string is an event listener name, otherwise `false`.
13
+ * @private
14
+ */
9
15
  function isEventListener(name) {
10
- return /^on[A-Z]/.test(name);
16
+ return /^on[A-Z]/.test(name);
11
17
  }
18
+ /**
19
+ * Determines if a given value is a render prop.
20
+ *
21
+ * A render prop is a function that is used to dynamically generate
22
+ * UI elements. This function checks if the provided value is a function
23
+ * and not an event listener.
24
+ *
25
+ * @param name - The name of the prop.
26
+ * @param value - The value of the prop to check.
27
+ * @returns `true` if the value is a render prop, otherwise `false`.
28
+ */
12
29
  function isRenderProp(name, value) {
13
- return typeof value === "function" && !isEventListener(name);
30
+ return typeof value === "function" && !isEventListener(name);
14
31
  }
32
+ /**
33
+ * Executes a function or returns a value from the given data object.
34
+ *
35
+ * @param name - The name of the property to execute or retrieve.
36
+ * @param data - The data object containing the property.
37
+ * @param args - The arguments to pass if the property is a function.
38
+ * @returns The result of the function execution or the value of the property.
39
+ * @private
40
+ */
15
41
  function execute(name, data, args) {
16
- const value = data[name];
17
- if (isRenderProp(name, value)) return value(args);
18
- return value;
42
+ const value = data[name];
43
+ if (isRenderProp(name, value)) return value(args);
44
+ return value;
19
45
  }
46
+ /**
47
+ * Retrieves a property value, potentially overridden by a slotted value.
48
+ *
49
+ * @param name - The name of the property to retrieve.
50
+ * @param options.props - The original properties.
51
+ * @param options.slots - The slotted values that can override the original properties.
52
+ * @param options.state - The current state.
53
+ * @param options.original - The original value of the property.
54
+ * @returns The original property value or the overridden value if provided.
55
+ */
20
56
  function renderProp(name, args) {
21
- const { props, slots, original } = args;
22
- return execute(name, slots, args) || execute(name, props, args) || original;
57
+ const { props, slots, original } = args;
58
+ return execute(name, slots, args) || execute(name, props, args) || original;
23
59
  }
60
+ /**
61
+ * Merges multiple refs into a single ref callback.
62
+ *
63
+ * @param refs - Array of refs to merge (can include undefined/null).
64
+ * @returns A single merged ref, undefined if no refs provided.
65
+ * @private
66
+ */
24
67
  function mergeRefList(refs) {
25
- const filtered = refs.filter((ref) => ref != null);
26
- if (!filtered.length) return void 0;
27
- if (filtered.length === 1) return filtered[0];
28
- return utils.mergeRefs(...filtered);
68
+ const filtered = refs.filter((ref) => ref != null);
69
+ if (!filtered.length) return void 0;
70
+ if (filtered.length === 1) return filtered[0];
71
+ return (0, _react_aria_utils.mergeRefs)(...filtered);
29
72
  }
73
+ /**
74
+ * Hook that merges props with slotted props and provides a proxy for accessing them.
75
+ *
76
+ * @param args - The initial props to use, or array when using rest parameters.
77
+ * @param state - The state object to use.
78
+ * @param forwardedRef - The ref forwarded to the component.
79
+ * @returns An object containing the proxy based props object and the apply function.
80
+ * @throws {BentoError} If the hook is used outside of a @bento/slots component.
81
+ *
82
+ * @example
83
+ * const { props, apply, ref } = useProps({ foo: 'bar' }, {}, forwardedRef);
84
+ * if (props.a) doSomething()
85
+ * return <a {...apply({ className: 'foo' }, ['ref']) } ref={ref}>{ props.children }</a>;
86
+ *
87
+ * @example
88
+ * // With rest parameters
89
+ * function Component(...rest) {
90
+ * const { props, apply, ref } = useProps(rest);
91
+ * return <div {...apply()} />;
92
+ * }
93
+ */
30
94
  function useProps(...rest) {
31
- let forwardedRef;
32
- let args;
33
- let state;
34
- if (Array.isArray(rest[0])) {
35
- [args, forwardedRef] = rest[0];
36
- state = rest[1];
37
- } else {
38
- [args, state, forwardedRef] = rest;
39
- }
40
- const { slots } = react.useContext(box.Box);
41
- const [props, internal] = internalProps.useInternalProps(args);
42
- const { namespace, assigned } = slots;
43
- const dot = namespace.join(".");
44
- const slotted = assigned[dot] || {};
45
- const ref = mergeRefList([
46
- props?.ref,
47
- slotted?.ref,
48
- forwardedRef
49
- ]);
50
- const slotNoRef = { ...slotted };
51
- const propsNoRef = { ...props };
52
- delete slotNoRef.ref;
53
- delete propsNoRef.ref;
54
- const propsy = { ...internal, ...propsNoRef, ...slotNoRef };
55
- function apply(attributes, except) {
56
- const data = attributes || propsy;
57
- const returned = {};
58
- function reduce(memo, key) {
59
- if (except && except.includes(key)) return memo;
60
- memo[key] = renderProp(key, {
61
- props: { ...props, ...internal },
62
- original: data[key],
63
- slots: slotted,
64
- state
65
- });
66
- return memo;
67
- }
68
- let result;
69
- if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);
70
- else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));
71
- if (except && except.includes("ref")) return result;
72
- if (ref) result.ref = ref;
73
- return result;
74
- }
75
- return {
76
- props: new Proxy(propsy, {
77
- get: function getter(_, name) {
78
- if (name === "ref") return ref;
79
- return renderProp(name, {
80
- original: isRenderProp(name, props[name]) ? void 0 : props[name],
81
- props: { ...props, ...internal },
82
- slots: slotted,
83
- state
84
- });
85
- }
86
- }),
87
- apply,
88
- ref
89
- };
95
+ let forwardedRef;
96
+ let args;
97
+ let state;
98
+ if (Array.isArray(rest[0])) {
99
+ [args, forwardedRef] = rest[0];
100
+ state = rest[1];
101
+ } else [args, state, forwardedRef] = rest;
102
+ const { slots } = (0, react.useContext)(_bento_box.Box);
103
+ const [props, internal] = (0, _bento_internal_props.useInternalProps)(args);
104
+ const { namespace, assigned } = slots;
105
+ const slotted = assigned[namespace.join(".")] || {};
106
+ const ref = mergeRefList([
107
+ props?.ref,
108
+ slotted?.ref,
109
+ forwardedRef
110
+ ]);
111
+ const slotNoRef = { ...slotted };
112
+ const propsNoRef = { ...props };
113
+ delete slotNoRef.ref;
114
+ delete propsNoRef.ref;
115
+ const propsy = {
116
+ ...internal,
117
+ ...propsNoRef,
118
+ ...slotNoRef
119
+ };
120
+ /**
121
+ * Applies the given attributes to an object.
122
+ *
123
+ * @param attributes - The attributes to apply. If not provided, defaults to `propsy`.
124
+ * @param except - An array of keys to exclude from the resulting object.
125
+ * @returns The resulting object with applied attributes.
126
+ * @public
127
+ */
128
+ function apply(attributes, except) {
129
+ const data = attributes || propsy;
130
+ const returned = {};
131
+ function reduce(memo, key) {
132
+ if (except && except.includes(key)) return memo;
133
+ memo[key] = renderProp(key, {
134
+ props: {
135
+ ...props,
136
+ ...internal
137
+ },
138
+ original: data[key],
139
+ slots: slotted,
140
+ state
141
+ });
142
+ return memo;
143
+ }
144
+ let result;
145
+ if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);
146
+ else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));
147
+ if (except && except.includes("ref")) return result;
148
+ if (ref) result.ref = ref;
149
+ return result;
150
+ }
151
+ return {
152
+ props: new Proxy(propsy, { get: function getter(_, name) {
153
+ if (name === "ref") return ref;
154
+ return renderProp(name, {
155
+ original: isRenderProp(name, props[name]) ? void 0 : props[name],
156
+ props: {
157
+ ...props,
158
+ ...internal
159
+ },
160
+ slots: slotted,
161
+ state
162
+ });
163
+ } }),
164
+ apply,
165
+ ref
166
+ };
90
167
  }
91
-
168
+ //#endregion
92
169
  exports.execute = execute;
93
170
  exports.isEventListener = isEventListener;
94
171
  exports.isRenderProp = isRenderProp;
95
172
  exports.renderProp = renderProp;
96
173
  exports.useProps = useProps;
97
- //# sourceMappingURL=index.cjs.map
174
+
98
175
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["mergeRefs","useContext","Box","useInternalProps"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Box, type BoxContext } from '@bento/box';\nimport { useInternalProps } from '@bento/internal-props';\nimport { AnyObject } from '@bento/types';\nimport { mergeRefs } from '@react-aria/utils';\nimport { useContext } from 'react';\nimport type { ForwardedRef, Ref } from 'react';\n\nexport interface RenderPropData {\n /**\n * If the component is assigning a default value to the given prop,\n * the original value be a reference to the previous assigned value.\n * @default The original assigned value\n */\n original?: unknown;\n\n /** All the props that were passed to the component. @default {} */\n props: AnyObject;\n\n /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */\n slots: AnyObject;\n\n /** The exposed state of the component. @default {} */\n state: AnyObject;\n}\n\n/**\n * Checks if the given string is an event listener name. An event listener name\n * is defined as a string that starts with \"on\" followed by an uppercase letter.\n *\n * @param name - The string to check.\n * @returns `true` if the string is an event listener name, otherwise `false`.\n * @private\n */\nexport function isEventListener(name: string): boolean {\n return /^on[A-Z]/.test(name);\n}\n\n/**\n * Determines if a given value is a render prop.\n *\n * A render prop is a function that is used to dynamically generate\n * UI elements. This function checks if the provided value is a function\n * and not an event listener.\n *\n * @param name - The name of the prop.\n * @param value - The value of the prop to check.\n * @returns `true` if the value is a render prop, otherwise `false`.\n */\nexport function isRenderProp(name: string, value: any): boolean {\n return typeof value === 'function' && !isEventListener(name);\n}\n\n/**\n * Executes a function or returns a value from the given data object.\n *\n * @param name - The name of the property to execute or retrieve.\n * @param data - The data object containing the property.\n * @param args - The arguments to pass if the property is a function.\n * @returns The result of the function execution or the value of the property.\n * @private\n */\nexport function execute(name: string, data: AnyObject, args: RenderPropData): any {\n const value = data[name];\n\n if (isRenderProp(name, value)) return value(args);\n return value;\n}\n\n/**\n * Retrieves a property value, potentially overridden by a slotted value.\n *\n * @param name - The name of the property to retrieve.\n * @param options.props - The original properties.\n * @param options.slots - The slotted values that can override the original properties.\n * @param options.state - The current state.\n * @param options.original - The original value of the property.\n * @returns The original property value or the overridden value if provided.\n */\nexport function renderProp(name: string, args: RenderPropData): any {\n const { props, slots, original } = args;\n\n return execute(name, slots, args) || execute(name, props, args) || original;\n}\n\n/**\n * Merges multiple refs into a single ref callback.\n *\n * @param refs - Array of refs to merge (can include undefined/null).\n * @returns A single merged ref, undefined if no refs provided.\n * @private\n */\nfunction mergeRefList(refs: Array<ForwardedRef<any> | Ref<any> | undefined>): Ref<any> | undefined {\n const filtered = refs.filter((ref): ref is ForwardedRef<any> | Ref<any> => ref != null);\n\n if (!filtered.length) return undefined;\n if (filtered.length === 1) return filtered[0] as Ref<any>;\n\n return mergeRefs(...(filtered as Array<Ref<any>>)) as Ref<any>;\n}\n\nexport interface Returns {\n /**\n * Proxy object that have access to the original props, slotted values, and internal props. When\n * accessing a property, it will first check the slotted values, then the original props, and finally\n * the internal props. If the property is a render prop, it will execute the function with the provided\n * arguments.\n *\n * @default { ...props, ...slots }\n */\n props: AnyObject;\n /**\n * Applies the given attributes as default values to the props. If no attributes are provided, it will\n * use the props as default values. The resulting object will contain all the properties of the props,\n * except for the ones specified in the `except` array. The values of the properties will be the result\n * of executing the render prop function with the provided arguments.\n *\n * @default function(attr)\n */\n apply: (attributes?: object, except?: string[]) => object;\n /**\n * The merged ref combining forwarded refs with any ref supplied via slots.\n */\n ref?: Ref<any>;\n}\n\n/**\n * Hook that merges props with slotted props and provides a proxy for accessing them.\n *\n * @param args - The initial props to use, or array when using rest parameters.\n * @param state - The state object to use.\n * @param forwardedRef - The ref forwarded to the component.\n * @returns An object containing the proxy based props object and the apply function.\n * @throws {BentoError} If the hook is used outside of a @bento/slots component.\n *\n * @example\n * const { props, apply, ref } = useProps({ foo: 'bar' }, {}, forwardedRef);\n * if (props.a) doSomething()\n * return <a {...apply({ className: 'foo' }, ['ref']) } ref={ref}>{ props.children }</a>;\n *\n * @example\n * // With rest parameters\n * function Component(...rest) {\n * const { props, apply, ref } = useProps(rest);\n * return <div {...apply()} />;\n * }\n */\nexport function useProps(...rest: any[]): Returns {\n let forwardedRef: ForwardedRef<any> | undefined;\n let args: AnyObject;\n let state: object;\n\n if (Array.isArray(rest[0])) {\n [args, forwardedRef] = rest[0];\n state = rest[1];\n } else {\n [args, state, forwardedRef] = rest;\n }\n\n const { slots } = useContext<BoxContext<AnyObject>>(Box);\n const [props, internal] = useInternalProps(args);\n const { namespace, assigned } = slots;\n const dot = namespace.join('.');\n const slotted = assigned[dot] || {};\n\n const ref = mergeRefList([\n (props as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n (slotted as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n forwardedRef\n ]);\n\n const slotNoRef = { ...slotted } as AnyObject;\n const propsNoRef = { ...props } as AnyObject;\n\n delete slotNoRef.ref;\n delete propsNoRef.ref;\n\n const propsy: AnyObject = { ...internal, ...propsNoRef, ...slotNoRef };\n\n /**\n * Applies the given attributes to an object.\n *\n * @param attributes - The attributes to apply. If not provided, defaults to `propsy`.\n * @param except - An array of keys to exclude from the resulting object.\n * @returns The resulting object with applied attributes.\n * @public\n */\n function apply(attributes?: object, except?: string[]): object {\n const data = (attributes || propsy) as AnyObject;\n const returned: AnyObject = {};\n\n function reduce(memo: AnyObject, key: string) {\n if (except && except.includes(key)) return memo;\n\n memo[key] = renderProp(key, {\n props: { ...props, ...internal },\n original: data[key],\n slots: slotted,\n state\n });\n\n return memo;\n }\n\n let result: AnyObject;\n\n if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);\n else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));\n\n // Always include the merged ref unless specifically excluded\n if (except && except.includes('ref')) return result;\n if (ref) result.ref = ref;\n\n return result;\n }\n\n return {\n props: new Proxy(propsy, {\n get: function getter(_: object, name: string) {\n if (name === 'ref') return ref;\n\n return renderProp(name, {\n original: isRenderProp(name, props[name]) ? undefined : props[name],\n props: { ...props, ...internal },\n slots: slotted,\n state\n });\n }\n }),\n apply,\n ref\n };\n}\n"]}
1
+ {"version":3,"file":"index.cjs","names":["Box"],"sources":["../src/index.ts"],"sourcesContent":["import { Box, type BoxContext } from '@bento/box';\nimport { useInternalProps } from '@bento/internal-props';\nimport { AnyObject } from '@bento/types';\nimport { mergeRefs } from '@react-aria/utils';\nimport { useContext } from 'react';\nimport type { ForwardedRef, Ref } from 'react';\n\nexport interface RenderPropData {\n /**\n * If the component is assigning a default value to the given prop,\n * the original value be a reference to the previous assigned value.\n * @default The original assigned value\n */\n original?: unknown;\n\n /** All the props that were passed to the component. @default {} */\n props: AnyObject;\n\n /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */\n slots: AnyObject;\n\n /** The exposed state of the component. @default {} */\n state: AnyObject;\n}\n\n/**\n * Checks if the given string is an event listener name. An event listener name\n * is defined as a string that starts with \"on\" followed by an uppercase letter.\n *\n * @param name - The string to check.\n * @returns `true` if the string is an event listener name, otherwise `false`.\n * @private\n */\nexport function isEventListener(name: string): boolean {\n return /^on[A-Z]/.test(name);\n}\n\n/**\n * Determines if a given value is a render prop.\n *\n * A render prop is a function that is used to dynamically generate\n * UI elements. This function checks if the provided value is a function\n * and not an event listener.\n *\n * @param name - The name of the prop.\n * @param value - The value of the prop to check.\n * @returns `true` if the value is a render prop, otherwise `false`.\n */\nexport function isRenderProp(name: string, value: any): boolean {\n return typeof value === 'function' && !isEventListener(name);\n}\n\n/**\n * Executes a function or returns a value from the given data object.\n *\n * @param name - The name of the property to execute or retrieve.\n * @param data - The data object containing the property.\n * @param args - The arguments to pass if the property is a function.\n * @returns The result of the function execution or the value of the property.\n * @private\n */\nexport function execute(name: string, data: AnyObject, args: RenderPropData): any {\n const value = data[name];\n\n if (isRenderProp(name, value)) return value(args);\n return value;\n}\n\n/**\n * Retrieves a property value, potentially overridden by a slotted value.\n *\n * @param name - The name of the property to retrieve.\n * @param options.props - The original properties.\n * @param options.slots - The slotted values that can override the original properties.\n * @param options.state - The current state.\n * @param options.original - The original value of the property.\n * @returns The original property value or the overridden value if provided.\n */\nexport function renderProp(name: string, args: RenderPropData): any {\n const { props, slots, original } = args;\n\n return execute(name, slots, args) || execute(name, props, args) || original;\n}\n\n/**\n * Merges multiple refs into a single ref callback.\n *\n * @param refs - Array of refs to merge (can include undefined/null).\n * @returns A single merged ref, undefined if no refs provided.\n * @private\n */\nfunction mergeRefList(refs: Array<ForwardedRef<any> | Ref<any> | undefined>): Ref<any> | undefined {\n const filtered = refs.filter((ref): ref is ForwardedRef<any> | Ref<any> => ref != null);\n\n if (!filtered.length) return undefined;\n if (filtered.length === 1) return filtered[0] as Ref<any>;\n\n return mergeRefs(...(filtered as Array<Ref<any>>)) as Ref<any>;\n}\n\nexport interface Returns {\n /**\n * Proxy object that have access to the original props, slotted values, and internal props. When\n * accessing a property, it will first check the slotted values, then the original props, and finally\n * the internal props. If the property is a render prop, it will execute the function with the provided\n * arguments.\n *\n * @default { ...props, ...slots }\n */\n props: AnyObject;\n /**\n * Applies the given attributes as default values to the props. If no attributes are provided, it will\n * use the props as default values. The resulting object will contain all the properties of the props,\n * except for the ones specified in the `except` array. The values of the properties will be the result\n * of executing the render prop function with the provided arguments.\n *\n * @default function(attr)\n */\n apply: (attributes?: object, except?: string[]) => object;\n /**\n * The merged ref combining forwarded refs with any ref supplied via slots.\n */\n ref?: Ref<any>;\n}\n\n/**\n * Hook that merges props with slotted props and provides a proxy for accessing them.\n *\n * @param args - The initial props to use, or array when using rest parameters.\n * @param state - The state object to use.\n * @param forwardedRef - The ref forwarded to the component.\n * @returns An object containing the proxy based props object and the apply function.\n * @throws {BentoError} If the hook is used outside of a @bento/slots component.\n *\n * @example\n * const { props, apply, ref } = useProps({ foo: 'bar' }, {}, forwardedRef);\n * if (props.a) doSomething()\n * return <a {...apply({ className: 'foo' }, ['ref']) } ref={ref}>{ props.children }</a>;\n *\n * @example\n * // With rest parameters\n * function Component(...rest) {\n * const { props, apply, ref } = useProps(rest);\n * return <div {...apply()} />;\n * }\n */\nexport function useProps(...rest: any[]): Returns {\n let forwardedRef: ForwardedRef<any> | undefined;\n let args: AnyObject;\n let state: object;\n\n if (Array.isArray(rest[0])) {\n [args, forwardedRef] = rest[0];\n state = rest[1];\n } else {\n [args, state, forwardedRef] = rest;\n }\n\n const { slots } = useContext<BoxContext<AnyObject>>(Box);\n const [props, internal] = useInternalProps(args);\n const { namespace, assigned } = slots;\n const dot = namespace.join('.');\n const slotted = assigned[dot] || {};\n\n const ref = mergeRefList([\n (props as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n (slotted as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n forwardedRef\n ]);\n\n const slotNoRef = { ...slotted } as AnyObject;\n const propsNoRef = { ...props } as AnyObject;\n\n delete slotNoRef.ref;\n delete propsNoRef.ref;\n\n const propsy: AnyObject = { ...internal, ...propsNoRef, ...slotNoRef };\n\n /**\n * Applies the given attributes to an object.\n *\n * @param attributes - The attributes to apply. If not provided, defaults to `propsy`.\n * @param except - An array of keys to exclude from the resulting object.\n * @returns The resulting object with applied attributes.\n * @public\n */\n function apply(attributes?: object, except?: string[]): object {\n const data = (attributes || propsy) as AnyObject;\n const returned: AnyObject = {};\n\n function reduce(memo: AnyObject, key: string) {\n if (except && except.includes(key)) return memo;\n\n memo[key] = renderProp(key, {\n props: { ...props, ...internal },\n original: data[key],\n slots: slotted,\n state\n });\n\n return memo;\n }\n\n let result: AnyObject;\n\n if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);\n else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));\n\n // Always include the merged ref unless specifically excluded\n if (except && except.includes('ref')) return result;\n if (ref) result.ref = ref;\n\n return result;\n }\n\n return {\n props: new Proxy(propsy, {\n get: function getter(_: object, name: string) {\n if (name === 'ref') return ref;\n\n return renderProp(name, {\n original: isRenderProp(name, props[name]) ? undefined : props[name],\n props: { ...props, ...internal },\n slots: slotted,\n state\n });\n }\n }),\n apply,\n ref\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAiCA,SAAgB,gBAAgB,MAAuB;CACrD,OAAO,WAAW,KAAK,IAAI;AAC7B;;;;;;;;;;;;AAaA,SAAgB,aAAa,MAAc,OAAqB;CAC9D,OAAO,OAAO,UAAU,cAAc,CAAC,gBAAgB,IAAI;AAC7D;;;;;;;;;;AAWA,SAAgB,QAAQ,MAAc,MAAiB,MAA2B;CAChF,MAAM,QAAQ,KAAK;CAEnB,IAAI,aAAa,MAAM,KAAK,GAAG,OAAO,MAAM,IAAI;CAChD,OAAO;AACT;;;;;;;;;;;AAYA,SAAgB,WAAW,MAAc,MAA2B;CAClE,MAAM,EAAE,OAAO,OAAO,aAAa;CAEnC,OAAO,QAAQ,MAAM,OAAO,IAAI,KAAK,QAAQ,MAAM,OAAO,IAAI,KAAK;AACrE;;;;;;;;AASA,SAAS,aAAa,MAA6E;CACjG,MAAM,WAAW,KAAK,QAAQ,QAA6C,OAAO,IAAI;CAEtF,IAAI,CAAC,SAAS,QAAQ,OAAO,KAAA;CAC7B,IAAI,SAAS,WAAW,GAAG,OAAO,SAAS;CAE3C,QAAA,GAAA,kBAAA,WAAiB,GAAI,QAA4B;AACnD;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,SAAS,GAAG,MAAsB;CAChD,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,IAAI,MAAM,QAAQ,KAAK,EAAE,GAAG;EAC1B,CAAC,MAAM,gBAAgB,KAAK;EAC5B,QAAQ,KAAK;CACf,OACE,CAAC,MAAM,OAAO,gBAAgB;CAGhC,MAAM,EAAE,WAAA,GAAA,MAAA,YAA4CA,WAAAA,GAAG;CACvD,MAAM,CAAC,OAAO,aAAA,GAAA,sBAAA,kBAA6B,IAAI;CAC/C,MAAM,EAAE,WAAW,aAAa;CAEhC,MAAM,UAAU,SADJ,UAAU,KAAK,GACA,MAAM,CAAC;CAElC,MAAM,MAAM,aAAa;EACtB,OAAqB;EACrB,SAAuB;EACxB;CACF,CAAC;CAED,MAAM,YAAY,EAAE,GAAG,QAAQ;CAC/B,MAAM,aAAa,EAAE,GAAG,MAAM;CAE9B,OAAO,UAAU;CACjB,OAAO,WAAW;CAElB,MAAM,SAAoB;EAAE,GAAG;EAAU,GAAG;EAAY,GAAG;CAAU;;;;;;;;;CAUrE,SAAS,MAAM,YAAqB,QAA2B;EAC7D,MAAM,OAAQ,cAAc;EAC5B,MAAM,WAAsB,CAAC;EAE7B,SAAS,OAAO,MAAiB,KAAa;GAC5C,IAAI,UAAU,OAAO,SAAS,GAAG,GAAG,OAAO;GAE3C,KAAK,OAAO,WAAW,KAAK;IAC1B,OAAO;KAAE,GAAG;KAAO,GAAG;IAAS;IAC/B,UAAU,KAAK;IACf,OAAO;IACP;GACF,CAAC;GAED,OAAO;EACT;EAEA,IAAI;EAEJ,IAAI,CAAC,YAAY,SAAS,OAAO,KAAK,MAAM,EAAE,OAAO,QAAQ,QAAQ;OAChE,SAAS,OAAO,KAAK,MAAM,EAAE,OAAO,QAAQ,OAAO,KAAK,UAAU,EAAE,OAAO,QAAQ,QAAQ,CAAC;EAGjG,IAAI,UAAU,OAAO,SAAS,KAAK,GAAG,OAAO;EAC7C,IAAI,KAAK,OAAO,MAAM;EAEtB,OAAO;CACT;CAEA,OAAO;EACL,OAAO,IAAI,MAAM,QAAQ,EACvB,KAAK,SAAS,OAAO,GAAW,MAAc;GAC5C,IAAI,SAAS,OAAO,OAAO;GAE3B,OAAO,WAAW,MAAM;IACtB,UAAU,aAAa,MAAM,MAAM,KAAK,IAAI,KAAA,IAAY,MAAM;IAC9D,OAAO;KAAE,GAAG;KAAO,GAAG;IAAS;IAC/B,OAAO;IACP;GACF,CAAC;EACH,EACF,CAAC;EACD;EACA;CACF;AACF"}
package/dist/index.d.cts CHANGED
@@ -1,19 +1,20 @@
1
- import { AnyObject } from '@bento/types';
2
- import { Ref } from 'react';
1
+ import { AnyObject } from "@bento/types";
2
+ import { Ref } from "react";
3
3
 
4
+ //#region src/index.d.ts
4
5
  interface RenderPropData {
5
- /**
6
- * If the component is assigning a default value to the given prop,
7
- * the original value be a reference to the previous assigned value.
8
- * @default The original assigned value
9
- */
10
- original?: unknown;
11
- /** All the props that were passed to the component. @default {} */
12
- props: AnyObject;
13
- /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */
14
- slots: AnyObject;
15
- /** The exposed state of the component. @default {} */
16
- state: AnyObject;
6
+ /**
7
+ * If the component is assigning a default value to the given prop,
8
+ * the original value be a reference to the previous assigned value.
9
+ * @default The original assigned value
10
+ */
11
+ original?: unknown;
12
+ /** All the props that were passed to the component. @default {} */
13
+ props: AnyObject;
14
+ /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */
15
+ slots: AnyObject;
16
+ /** The exposed state of the component. @default {} */
17
+ state: AnyObject;
17
18
  }
18
19
  /**
19
20
  * Checks if the given string is an event listener name. An event listener name
@@ -58,28 +59,28 @@ declare function execute(name: string, data: AnyObject, args: RenderPropData): a
58
59
  */
59
60
  declare function renderProp(name: string, args: RenderPropData): any;
60
61
  interface Returns {
61
- /**
62
- * Proxy object that have access to the original props, slotted values, and internal props. When
63
- * accessing a property, it will first check the slotted values, then the original props, and finally
64
- * the internal props. If the property is a render prop, it will execute the function with the provided
65
- * arguments.
66
- *
67
- * @default { ...props, ...slots }
68
- */
69
- props: AnyObject;
70
- /**
71
- * Applies the given attributes as default values to the props. If no attributes are provided, it will
72
- * use the props as default values. The resulting object will contain all the properties of the props,
73
- * except for the ones specified in the `except` array. The values of the properties will be the result
74
- * of executing the render prop function with the provided arguments.
75
- *
76
- * @default function(attr)
77
- */
78
- apply: (attributes?: object, except?: string[]) => object;
79
- /**
80
- * The merged ref combining forwarded refs with any ref supplied via slots.
81
- */
82
- ref?: Ref<any>;
62
+ /**
63
+ * Proxy object that have access to the original props, slotted values, and internal props. When
64
+ * accessing a property, it will first check the slotted values, then the original props, and finally
65
+ * the internal props. If the property is a render prop, it will execute the function with the provided
66
+ * arguments.
67
+ *
68
+ * @default { ...props, ...slots }
69
+ */
70
+ props: AnyObject;
71
+ /**
72
+ * Applies the given attributes as default values to the props. If no attributes are provided, it will
73
+ * use the props as default values. The resulting object will contain all the properties of the props,
74
+ * except for the ones specified in the `except` array. The values of the properties will be the result
75
+ * of executing the render prop function with the provided arguments.
76
+ *
77
+ * @default function(attr)
78
+ */
79
+ apply: (attributes?: object, except?: string[]) => object;
80
+ /**
81
+ * The merged ref combining forwarded refs with any ref supplied via slots.
82
+ */
83
+ ref?: Ref<any>;
83
84
  }
84
85
  /**
85
86
  * Hook that merges props with slotted props and provides a proxy for accessing them.
@@ -103,5 +104,6 @@ interface Returns {
103
104
  * }
104
105
  */
105
106
  declare function useProps(...rest: any[]): Returns;
106
-
107
- export { type RenderPropData, type Returns, execute, isEventListener, isRenderProp, renderProp, useProps };
107
+ //#endregion
108
+ export { RenderPropData, Returns, execute, isEventListener, isRenderProp, renderProp, useProps };
109
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;UAOiB,cAAA;;AAAjB;;;;EAME,QAAA;EASO;EANP,KAAA,EAAO,SAAA;EAMS;EAHhB,KAAA,EAAO,SAAA;EAHP;EAMA,KAAA,EAAO,SAAA;AAAA;;;;;AAAS;AAWlB;;;iBAAgB,eAAA,CAAgB,IAAY;AAAA;AAe5C;;;;AAAqD;AAarD;;;;;AA5B4C,iBAe5B,YAAA,CAAa,IAAA,UAAc,KAAU;;;;;AAasB;AAiB3E;;;;iBAjBgB,OAAA,CAAQ,IAAA,UAAc,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,cAAc;;;;AAiBd;AAsB7D;;;;;;iBAtBgB,UAAA,CAAW,IAAA,UAAc,IAAA,EAAM,cAAc;AAAA,UAsB5C,OAAA;EAkBc;;;;AAIpB;AAwBX;;;EArCE,KAAA,EAAO,SAAA;EAqCwC;;;;;;;;EA5B/C,KAAA,GAAQ,UAAA,WAAqB,MAAA;;;;EAI7B,GAAA,GAAM,GAAG;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAwBK,QAAA,IAAY,IAAA,UAAc,OAAO"}
@@ -1,19 +1,20 @@
1
- import { AnyObject } from '@bento/types';
2
- import { Ref } from 'react';
1
+ import { Ref } from "react";
2
+ import { AnyObject } from "@bento/types";
3
3
 
4
+ //#region src/index.d.ts
4
5
  interface RenderPropData {
5
- /**
6
- * If the component is assigning a default value to the given prop,
7
- * the original value be a reference to the previous assigned value.
8
- * @default The original assigned value
9
- */
10
- original?: unknown;
11
- /** All the props that were passed to the component. @default {} */
12
- props: AnyObject;
13
- /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */
14
- slots: AnyObject;
15
- /** The exposed state of the component. @default {} */
16
- state: AnyObject;
6
+ /**
7
+ * If the component is assigning a default value to the given prop,
8
+ * the original value be a reference to the previous assigned value.
9
+ * @default The original assigned value
10
+ */
11
+ original?: unknown;
12
+ /** All the props that were passed to the component. @default {} */
13
+ props: AnyObject;
14
+ /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */
15
+ slots: AnyObject;
16
+ /** The exposed state of the component. @default {} */
17
+ state: AnyObject;
17
18
  }
18
19
  /**
19
20
  * Checks if the given string is an event listener name. An event listener name
@@ -58,28 +59,28 @@ declare function execute(name: string, data: AnyObject, args: RenderPropData): a
58
59
  */
59
60
  declare function renderProp(name: string, args: RenderPropData): any;
60
61
  interface Returns {
61
- /**
62
- * Proxy object that have access to the original props, slotted values, and internal props. When
63
- * accessing a property, it will first check the slotted values, then the original props, and finally
64
- * the internal props. If the property is a render prop, it will execute the function with the provided
65
- * arguments.
66
- *
67
- * @default { ...props, ...slots }
68
- */
69
- props: AnyObject;
70
- /**
71
- * Applies the given attributes as default values to the props. If no attributes are provided, it will
72
- * use the props as default values. The resulting object will contain all the properties of the props,
73
- * except for the ones specified in the `except` array. The values of the properties will be the result
74
- * of executing the render prop function with the provided arguments.
75
- *
76
- * @default function(attr)
77
- */
78
- apply: (attributes?: object, except?: string[]) => object;
79
- /**
80
- * The merged ref combining forwarded refs with any ref supplied via slots.
81
- */
82
- ref?: Ref<any>;
62
+ /**
63
+ * Proxy object that have access to the original props, slotted values, and internal props. When
64
+ * accessing a property, it will first check the slotted values, then the original props, and finally
65
+ * the internal props. If the property is a render prop, it will execute the function with the provided
66
+ * arguments.
67
+ *
68
+ * @default { ...props, ...slots }
69
+ */
70
+ props: AnyObject;
71
+ /**
72
+ * Applies the given attributes as default values to the props. If no attributes are provided, it will
73
+ * use the props as default values. The resulting object will contain all the properties of the props,
74
+ * except for the ones specified in the `except` array. The values of the properties will be the result
75
+ * of executing the render prop function with the provided arguments.
76
+ *
77
+ * @default function(attr)
78
+ */
79
+ apply: (attributes?: object, except?: string[]) => object;
80
+ /**
81
+ * The merged ref combining forwarded refs with any ref supplied via slots.
82
+ */
83
+ ref?: Ref<any>;
83
84
  }
84
85
  /**
85
86
  * Hook that merges props with slotted props and provides a proxy for accessing them.
@@ -103,5 +104,6 @@ interface Returns {
103
104
  * }
104
105
  */
105
106
  declare function useProps(...rest: any[]): Returns;
106
-
107
- export { type RenderPropData, type Returns, execute, isEventListener, isRenderProp, renderProp, useProps };
107
+ //#endregion
108
+ export { RenderPropData, Returns, execute, isEventListener, isRenderProp, renderProp, useProps };
109
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;UAOiB,cAAA;;AAAjB;;;;EAME,QAAA;EASO;EANP,KAAA,EAAO,SAAA;EAMS;EAHhB,KAAA,EAAO,SAAA;EAHP;EAMA,KAAA,EAAO,SAAA;AAAA;;;;;AAAS;AAWlB;;;iBAAgB,eAAA,CAAgB,IAAY;AAAA;AAe5C;;;;AAAqD;AAarD;;;;;AA5B4C,iBAe5B,YAAA,CAAa,IAAA,UAAc,KAAU;;;;;AAasB;AAiB3E;;;;iBAjBgB,OAAA,CAAQ,IAAA,UAAc,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,cAAc;;;;AAiBd;AAsB7D;;;;;;iBAtBgB,UAAA,CAAW,IAAA,UAAc,IAAA,EAAM,cAAc;AAAA,UAsB5C,OAAA;EAkBc;;;;AAIpB;AAwBX;;;EArCE,KAAA,EAAO,SAAA;EAqCwC;;;;;;;;EA5B/C,KAAA,GAAQ,UAAA,WAAqB,MAAA;;;;EAI7B,GAAA,GAAM,GAAG;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAwBK,QAAA,IAAY,IAAA,UAAc,OAAO"}
package/dist/index.mjs ADDED
@@ -0,0 +1,170 @@
1
+ import { Box } from "@bento/box";
2
+ import { useInternalProps } from "@bento/internal-props";
3
+ import { mergeRefs } from "@react-aria/utils";
4
+ import { useContext } from "react";
5
+ //#region src/index.ts
6
+ /**
7
+ * Checks if the given string is an event listener name. An event listener name
8
+ * is defined as a string that starts with "on" followed by an uppercase letter.
9
+ *
10
+ * @param name - The string to check.
11
+ * @returns `true` if the string is an event listener name, otherwise `false`.
12
+ * @private
13
+ */
14
+ function isEventListener(name) {
15
+ return /^on[A-Z]/.test(name);
16
+ }
17
+ /**
18
+ * Determines if a given value is a render prop.
19
+ *
20
+ * A render prop is a function that is used to dynamically generate
21
+ * UI elements. This function checks if the provided value is a function
22
+ * and not an event listener.
23
+ *
24
+ * @param name - The name of the prop.
25
+ * @param value - The value of the prop to check.
26
+ * @returns `true` if the value is a render prop, otherwise `false`.
27
+ */
28
+ function isRenderProp(name, value) {
29
+ return typeof value === "function" && !isEventListener(name);
30
+ }
31
+ /**
32
+ * Executes a function or returns a value from the given data object.
33
+ *
34
+ * @param name - The name of the property to execute or retrieve.
35
+ * @param data - The data object containing the property.
36
+ * @param args - The arguments to pass if the property is a function.
37
+ * @returns The result of the function execution or the value of the property.
38
+ * @private
39
+ */
40
+ function execute(name, data, args) {
41
+ const value = data[name];
42
+ if (isRenderProp(name, value)) return value(args);
43
+ return value;
44
+ }
45
+ /**
46
+ * Retrieves a property value, potentially overridden by a slotted value.
47
+ *
48
+ * @param name - The name of the property to retrieve.
49
+ * @param options.props - The original properties.
50
+ * @param options.slots - The slotted values that can override the original properties.
51
+ * @param options.state - The current state.
52
+ * @param options.original - The original value of the property.
53
+ * @returns The original property value or the overridden value if provided.
54
+ */
55
+ function renderProp(name, args) {
56
+ const { props, slots, original } = args;
57
+ return execute(name, slots, args) || execute(name, props, args) || original;
58
+ }
59
+ /**
60
+ * Merges multiple refs into a single ref callback.
61
+ *
62
+ * @param refs - Array of refs to merge (can include undefined/null).
63
+ * @returns A single merged ref, undefined if no refs provided.
64
+ * @private
65
+ */
66
+ function mergeRefList(refs) {
67
+ const filtered = refs.filter((ref) => ref != null);
68
+ if (!filtered.length) return void 0;
69
+ if (filtered.length === 1) return filtered[0];
70
+ return mergeRefs(...filtered);
71
+ }
72
+ /**
73
+ * Hook that merges props with slotted props and provides a proxy for accessing them.
74
+ *
75
+ * @param args - The initial props to use, or array when using rest parameters.
76
+ * @param state - The state object to use.
77
+ * @param forwardedRef - The ref forwarded to the component.
78
+ * @returns An object containing the proxy based props object and the apply function.
79
+ * @throws {BentoError} If the hook is used outside of a @bento/slots component.
80
+ *
81
+ * @example
82
+ * const { props, apply, ref } = useProps({ foo: 'bar' }, {}, forwardedRef);
83
+ * if (props.a) doSomething()
84
+ * return <a {...apply({ className: 'foo' }, ['ref']) } ref={ref}>{ props.children }</a>;
85
+ *
86
+ * @example
87
+ * // With rest parameters
88
+ * function Component(...rest) {
89
+ * const { props, apply, ref } = useProps(rest);
90
+ * return <div {...apply()} />;
91
+ * }
92
+ */
93
+ function useProps(...rest) {
94
+ let forwardedRef;
95
+ let args;
96
+ let state;
97
+ if (Array.isArray(rest[0])) {
98
+ [args, forwardedRef] = rest[0];
99
+ state = rest[1];
100
+ } else [args, state, forwardedRef] = rest;
101
+ const { slots } = useContext(Box);
102
+ const [props, internal] = useInternalProps(args);
103
+ const { namespace, assigned } = slots;
104
+ const slotted = assigned[namespace.join(".")] || {};
105
+ const ref = mergeRefList([
106
+ props?.ref,
107
+ slotted?.ref,
108
+ forwardedRef
109
+ ]);
110
+ const slotNoRef = { ...slotted };
111
+ const propsNoRef = { ...props };
112
+ delete slotNoRef.ref;
113
+ delete propsNoRef.ref;
114
+ const propsy = {
115
+ ...internal,
116
+ ...propsNoRef,
117
+ ...slotNoRef
118
+ };
119
+ /**
120
+ * Applies the given attributes to an object.
121
+ *
122
+ * @param attributes - The attributes to apply. If not provided, defaults to `propsy`.
123
+ * @param except - An array of keys to exclude from the resulting object.
124
+ * @returns The resulting object with applied attributes.
125
+ * @public
126
+ */
127
+ function apply(attributes, except) {
128
+ const data = attributes || propsy;
129
+ const returned = {};
130
+ function reduce(memo, key) {
131
+ if (except && except.includes(key)) return memo;
132
+ memo[key] = renderProp(key, {
133
+ props: {
134
+ ...props,
135
+ ...internal
136
+ },
137
+ original: data[key],
138
+ slots: slotted,
139
+ state
140
+ });
141
+ return memo;
142
+ }
143
+ let result;
144
+ if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);
145
+ else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));
146
+ if (except && except.includes("ref")) return result;
147
+ if (ref) result.ref = ref;
148
+ return result;
149
+ }
150
+ return {
151
+ props: new Proxy(propsy, { get: function getter(_, name) {
152
+ if (name === "ref") return ref;
153
+ return renderProp(name, {
154
+ original: isRenderProp(name, props[name]) ? void 0 : props[name],
155
+ props: {
156
+ ...props,
157
+ ...internal
158
+ },
159
+ slots: slotted,
160
+ state
161
+ });
162
+ } }),
163
+ apply,
164
+ ref
165
+ };
166
+ }
167
+ //#endregion
168
+ export { execute, isEventListener, isRenderProp, renderProp, useProps };
169
+
170
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { Box, type BoxContext } from '@bento/box';\nimport { useInternalProps } from '@bento/internal-props';\nimport { AnyObject } from '@bento/types';\nimport { mergeRefs } from '@react-aria/utils';\nimport { useContext } from 'react';\nimport type { ForwardedRef, Ref } from 'react';\n\nexport interface RenderPropData {\n /**\n * If the component is assigning a default value to the given prop,\n * the original value be a reference to the previous assigned value.\n * @default The original assigned value\n */\n original?: unknown;\n\n /** All the props that were passed to the component. @default {} */\n props: AnyObject;\n\n /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */\n slots: AnyObject;\n\n /** The exposed state of the component. @default {} */\n state: AnyObject;\n}\n\n/**\n * Checks if the given string is an event listener name. An event listener name\n * is defined as a string that starts with \"on\" followed by an uppercase letter.\n *\n * @param name - The string to check.\n * @returns `true` if the string is an event listener name, otherwise `false`.\n * @private\n */\nexport function isEventListener(name: string): boolean {\n return /^on[A-Z]/.test(name);\n}\n\n/**\n * Determines if a given value is a render prop.\n *\n * A render prop is a function that is used to dynamically generate\n * UI elements. This function checks if the provided value is a function\n * and not an event listener.\n *\n * @param name - The name of the prop.\n * @param value - The value of the prop to check.\n * @returns `true` if the value is a render prop, otherwise `false`.\n */\nexport function isRenderProp(name: string, value: any): boolean {\n return typeof value === 'function' && !isEventListener(name);\n}\n\n/**\n * Executes a function or returns a value from the given data object.\n *\n * @param name - The name of the property to execute or retrieve.\n * @param data - The data object containing the property.\n * @param args - The arguments to pass if the property is a function.\n * @returns The result of the function execution or the value of the property.\n * @private\n */\nexport function execute(name: string, data: AnyObject, args: RenderPropData): any {\n const value = data[name];\n\n if (isRenderProp(name, value)) return value(args);\n return value;\n}\n\n/**\n * Retrieves a property value, potentially overridden by a slotted value.\n *\n * @param name - The name of the property to retrieve.\n * @param options.props - The original properties.\n * @param options.slots - The slotted values that can override the original properties.\n * @param options.state - The current state.\n * @param options.original - The original value of the property.\n * @returns The original property value or the overridden value if provided.\n */\nexport function renderProp(name: string, args: RenderPropData): any {\n const { props, slots, original } = args;\n\n return execute(name, slots, args) || execute(name, props, args) || original;\n}\n\n/**\n * Merges multiple refs into a single ref callback.\n *\n * @param refs - Array of refs to merge (can include undefined/null).\n * @returns A single merged ref, undefined if no refs provided.\n * @private\n */\nfunction mergeRefList(refs: Array<ForwardedRef<any> | Ref<any> | undefined>): Ref<any> | undefined {\n const filtered = refs.filter((ref): ref is ForwardedRef<any> | Ref<any> => ref != null);\n\n if (!filtered.length) return undefined;\n if (filtered.length === 1) return filtered[0] as Ref<any>;\n\n return mergeRefs(...(filtered as Array<Ref<any>>)) as Ref<any>;\n}\n\nexport interface Returns {\n /**\n * Proxy object that have access to the original props, slotted values, and internal props. When\n * accessing a property, it will first check the slotted values, then the original props, and finally\n * the internal props. If the property is a render prop, it will execute the function with the provided\n * arguments.\n *\n * @default { ...props, ...slots }\n */\n props: AnyObject;\n /**\n * Applies the given attributes as default values to the props. If no attributes are provided, it will\n * use the props as default values. The resulting object will contain all the properties of the props,\n * except for the ones specified in the `except` array. The values of the properties will be the result\n * of executing the render prop function with the provided arguments.\n *\n * @default function(attr)\n */\n apply: (attributes?: object, except?: string[]) => object;\n /**\n * The merged ref combining forwarded refs with any ref supplied via slots.\n */\n ref?: Ref<any>;\n}\n\n/**\n * Hook that merges props with slotted props and provides a proxy for accessing them.\n *\n * @param args - The initial props to use, or array when using rest parameters.\n * @param state - The state object to use.\n * @param forwardedRef - The ref forwarded to the component.\n * @returns An object containing the proxy based props object and the apply function.\n * @throws {BentoError} If the hook is used outside of a @bento/slots component.\n *\n * @example\n * const { props, apply, ref } = useProps({ foo: 'bar' }, {}, forwardedRef);\n * if (props.a) doSomething()\n * return <a {...apply({ className: 'foo' }, ['ref']) } ref={ref}>{ props.children }</a>;\n *\n * @example\n * // With rest parameters\n * function Component(...rest) {\n * const { props, apply, ref } = useProps(rest);\n * return <div {...apply()} />;\n * }\n */\nexport function useProps(...rest: any[]): Returns {\n let forwardedRef: ForwardedRef<any> | undefined;\n let args: AnyObject;\n let state: object;\n\n if (Array.isArray(rest[0])) {\n [args, forwardedRef] = rest[0];\n state = rest[1];\n } else {\n [args, state, forwardedRef] = rest;\n }\n\n const { slots } = useContext<BoxContext<AnyObject>>(Box);\n const [props, internal] = useInternalProps(args);\n const { namespace, assigned } = slots;\n const dot = namespace.join('.');\n const slotted = assigned[dot] || {};\n\n const ref = mergeRefList([\n (props as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n (slotted as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n forwardedRef\n ]);\n\n const slotNoRef = { ...slotted } as AnyObject;\n const propsNoRef = { ...props } as AnyObject;\n\n delete slotNoRef.ref;\n delete propsNoRef.ref;\n\n const propsy: AnyObject = { ...internal, ...propsNoRef, ...slotNoRef };\n\n /**\n * Applies the given attributes to an object.\n *\n * @param attributes - The attributes to apply. If not provided, defaults to `propsy`.\n * @param except - An array of keys to exclude from the resulting object.\n * @returns The resulting object with applied attributes.\n * @public\n */\n function apply(attributes?: object, except?: string[]): object {\n const data = (attributes || propsy) as AnyObject;\n const returned: AnyObject = {};\n\n function reduce(memo: AnyObject, key: string) {\n if (except && except.includes(key)) return memo;\n\n memo[key] = renderProp(key, {\n props: { ...props, ...internal },\n original: data[key],\n slots: slotted,\n state\n });\n\n return memo;\n }\n\n let result: AnyObject;\n\n if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);\n else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));\n\n // Always include the merged ref unless specifically excluded\n if (except && except.includes('ref')) return result;\n if (ref) result.ref = ref;\n\n return result;\n }\n\n return {\n props: new Proxy(propsy, {\n get: function getter(_: object, name: string) {\n if (name === 'ref') return ref;\n\n return renderProp(name, {\n original: isRenderProp(name, props[name]) ? undefined : props[name],\n props: { ...props, ...internal },\n slots: slotted,\n state\n });\n }\n }),\n apply,\n ref\n };\n}\n"],"mappings":";;;;;;;;;;;;;AAiCA,SAAgB,gBAAgB,MAAuB;CACrD,OAAO,WAAW,KAAK,IAAI;AAC7B;;;;;;;;;;;;AAaA,SAAgB,aAAa,MAAc,OAAqB;CAC9D,OAAO,OAAO,UAAU,cAAc,CAAC,gBAAgB,IAAI;AAC7D;;;;;;;;;;AAWA,SAAgB,QAAQ,MAAc,MAAiB,MAA2B;CAChF,MAAM,QAAQ,KAAK;CAEnB,IAAI,aAAa,MAAM,KAAK,GAAG,OAAO,MAAM,IAAI;CAChD,OAAO;AACT;;;;;;;;;;;AAYA,SAAgB,WAAW,MAAc,MAA2B;CAClE,MAAM,EAAE,OAAO,OAAO,aAAa;CAEnC,OAAO,QAAQ,MAAM,OAAO,IAAI,KAAK,QAAQ,MAAM,OAAO,IAAI,KAAK;AACrE;;;;;;;;AASA,SAAS,aAAa,MAA6E;CACjG,MAAM,WAAW,KAAK,QAAQ,QAA6C,OAAO,IAAI;CAEtF,IAAI,CAAC,SAAS,QAAQ,OAAO,KAAA;CAC7B,IAAI,SAAS,WAAW,GAAG,OAAO,SAAS;CAE3C,OAAO,UAAU,GAAI,QAA4B;AACnD;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,SAAS,GAAG,MAAsB;CAChD,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,IAAI,MAAM,QAAQ,KAAK,EAAE,GAAG;EAC1B,CAAC,MAAM,gBAAgB,KAAK;EAC5B,QAAQ,KAAK;CACf,OACE,CAAC,MAAM,OAAO,gBAAgB;CAGhC,MAAM,EAAE,UAAU,WAAkC,GAAG;CACvD,MAAM,CAAC,OAAO,YAAY,iBAAiB,IAAI;CAC/C,MAAM,EAAE,WAAW,aAAa;CAEhC,MAAM,UAAU,SADJ,UAAU,KAAK,GACA,MAAM,CAAC;CAElC,MAAM,MAAM,aAAa;EACtB,OAAqB;EACrB,SAAuB;EACxB;CACF,CAAC;CAED,MAAM,YAAY,EAAE,GAAG,QAAQ;CAC/B,MAAM,aAAa,EAAE,GAAG,MAAM;CAE9B,OAAO,UAAU;CACjB,OAAO,WAAW;CAElB,MAAM,SAAoB;EAAE,GAAG;EAAU,GAAG;EAAY,GAAG;CAAU;;;;;;;;;CAUrE,SAAS,MAAM,YAAqB,QAA2B;EAC7D,MAAM,OAAQ,cAAc;EAC5B,MAAM,WAAsB,CAAC;EAE7B,SAAS,OAAO,MAAiB,KAAa;GAC5C,IAAI,UAAU,OAAO,SAAS,GAAG,GAAG,OAAO;GAE3C,KAAK,OAAO,WAAW,KAAK;IAC1B,OAAO;KAAE,GAAG;KAAO,GAAG;IAAS;IAC/B,UAAU,KAAK;IACf,OAAO;IACP;GACF,CAAC;GAED,OAAO;EACT;EAEA,IAAI;EAEJ,IAAI,CAAC,YAAY,SAAS,OAAO,KAAK,MAAM,EAAE,OAAO,QAAQ,QAAQ;OAChE,SAAS,OAAO,KAAK,MAAM,EAAE,OAAO,QAAQ,OAAO,KAAK,UAAU,EAAE,OAAO,QAAQ,QAAQ,CAAC;EAGjG,IAAI,UAAU,OAAO,SAAS,KAAK,GAAG,OAAO;EAC7C,IAAI,KAAK,OAAO,MAAM;EAEtB,OAAO;CACT;CAEA,OAAO;EACL,OAAO,IAAI,MAAM,QAAQ,EACvB,KAAK,SAAS,OAAO,GAAW,MAAc;GAC5C,IAAI,SAAS,OAAO,OAAO;GAE3B,OAAO,WAAW,MAAM;IACtB,UAAU,aAAa,MAAM,MAAM,KAAK,IAAI,KAAA,IAAY,MAAM;IAC9D,OAAO;KAAE,GAAG;KAAO,GAAG;IAAS;IAC/B,OAAO;IACP;GACF,CAAC;EACH,EACF,CAAC;EACD;EACA;CACF;AACF"}
package/package.json CHANGED
@@ -1,23 +1,22 @@
1
1
  {
2
2
  "name": "@bento/use-props",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Context aware props transformation for Bento",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
- "module": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
8
  "scripts": {
9
- "build": "tsup-node",
10
- "dev": "tsup-node --watch",
11
- "lint": "biome lint && tsc --noEmit",
12
- "posttest": "npm run lint",
13
- "prepublishOnly": "node ../../scripts/compile-readme.ts",
14
- "pretest": "npm run build",
9
+ "build": "tsdown",
10
+ "dev": "tsdown --watch",
11
+ "lint": "biome lint && tsgo --noEmit",
12
+ "prepublishOnly": "node ../../../scripts/compile-readme.ts",
15
13
  "test": "vitest --run",
16
- "test:watch": "vitest"
14
+ "test:watch": "vitest",
15
+ "typecheck": "tsgo --noEmit -p tsconfig.json"
17
16
  },
18
17
  "repository": {
19
18
  "type": "git",
20
- "url": "git+https://github.com/godaddy/bento.git"
19
+ "url": "git+https://github.com/godaddy/antares.git"
21
20
  },
22
21
  "keywords": [
23
22
  "bento",
@@ -32,9 +31,9 @@
32
31
  "author": "GoDaddy Operating Company, LLC",
33
32
  "license": "MIT",
34
33
  "bugs": {
35
- "url": "https://github.com/godaddy/bento/issues"
34
+ "url": "https://github.com/godaddy/antares/issues"
36
35
  },
37
- "homepage": "https://github.com/godaddy/bento#readme",
36
+ "homepage": "https://github.com/godaddy/antares#readme",
38
37
  "files": [
39
38
  "dist",
40
39
  "src",
@@ -43,10 +42,16 @@
43
42
  "dependencies": {
44
43
  "@bento/box": "^0.2.0",
45
44
  "@bento/internal-props": "^0.1.1",
46
- "@react-aria/utils": "^3.30.0"
45
+ "@bento/types": "^0.1.1",
46
+ "@react-aria/utils": "^3.34.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@bento/types": "^0.1.0"
49
+ "@types/react": "^19.2.15",
50
+ "@types/react-dom": "^19.2.3",
51
+ "tsdown": "^0.22.1",
52
+ "typescript": "^6.0.3",
53
+ "vitest": "^4.1.7",
54
+ "vitest-browser-react": "^2.2.0"
50
55
  },
51
56
  "peerDependencies": {
52
57
  "react": "18.x || 19.x",
@@ -55,8 +60,8 @@
55
60
  "exports": {
56
61
  ".": {
57
62
  "import": {
58
- "types": "./dist/index.d.ts",
59
- "default": "./dist/index.js"
63
+ "types": "./dist/index.d.mts",
64
+ "default": "./dist/index.mjs"
60
65
  },
61
66
  "require": {
62
67
  "types": "./dist/index.d.cts",
package/dist/index.js DELETED
@@ -1,92 +0,0 @@
1
- import { Box } from '@bento/box';
2
- import { useInternalProps } from '@bento/internal-props';
3
- import { mergeRefs } from '@react-aria/utils';
4
- import { useContext } from 'react';
5
-
6
- // src/index.ts
7
- function isEventListener(name) {
8
- return /^on[A-Z]/.test(name);
9
- }
10
- function isRenderProp(name, value) {
11
- return typeof value === "function" && !isEventListener(name);
12
- }
13
- function execute(name, data, args) {
14
- const value = data[name];
15
- if (isRenderProp(name, value)) return value(args);
16
- return value;
17
- }
18
- function renderProp(name, args) {
19
- const { props, slots, original } = args;
20
- return execute(name, slots, args) || execute(name, props, args) || original;
21
- }
22
- function mergeRefList(refs) {
23
- const filtered = refs.filter((ref) => ref != null);
24
- if (!filtered.length) return void 0;
25
- if (filtered.length === 1) return filtered[0];
26
- return mergeRefs(...filtered);
27
- }
28
- function useProps(...rest) {
29
- let forwardedRef;
30
- let args;
31
- let state;
32
- if (Array.isArray(rest[0])) {
33
- [args, forwardedRef] = rest[0];
34
- state = rest[1];
35
- } else {
36
- [args, state, forwardedRef] = rest;
37
- }
38
- const { slots } = useContext(Box);
39
- const [props, internal] = useInternalProps(args);
40
- const { namespace, assigned } = slots;
41
- const dot = namespace.join(".");
42
- const slotted = assigned[dot] || {};
43
- const ref = mergeRefList([
44
- props?.ref,
45
- slotted?.ref,
46
- forwardedRef
47
- ]);
48
- const slotNoRef = { ...slotted };
49
- const propsNoRef = { ...props };
50
- delete slotNoRef.ref;
51
- delete propsNoRef.ref;
52
- const propsy = { ...internal, ...propsNoRef, ...slotNoRef };
53
- function apply(attributes, except) {
54
- const data = attributes || propsy;
55
- const returned = {};
56
- function reduce(memo, key) {
57
- if (except && except.includes(key)) return memo;
58
- memo[key] = renderProp(key, {
59
- props: { ...props, ...internal },
60
- original: data[key],
61
- slots: slotted,
62
- state
63
- });
64
- return memo;
65
- }
66
- let result;
67
- if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);
68
- else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));
69
- if (except && except.includes("ref")) return result;
70
- if (ref) result.ref = ref;
71
- return result;
72
- }
73
- return {
74
- props: new Proxy(propsy, {
75
- get: function getter(_, name) {
76
- if (name === "ref") return ref;
77
- return renderProp(name, {
78
- original: isRenderProp(name, props[name]) ? void 0 : props[name],
79
- props: { ...props, ...internal },
80
- slots: slotted,
81
- state
82
- });
83
- }
84
- }),
85
- apply,
86
- ref
87
- };
88
- }
89
-
90
- export { execute, isEventListener, isRenderProp, renderProp, useProps };
91
- //# sourceMappingURL=index.js.map
92
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { Box, type BoxContext } from '@bento/box';\nimport { useInternalProps } from '@bento/internal-props';\nimport { AnyObject } from '@bento/types';\nimport { mergeRefs } from '@react-aria/utils';\nimport { useContext } from 'react';\nimport type { ForwardedRef, Ref } from 'react';\n\nexport interface RenderPropData {\n /**\n * If the component is assigning a default value to the given prop,\n * the original value be a reference to the previous assigned value.\n * @default The original assigned value\n */\n original?: unknown;\n\n /** All the props that were passed to the component. @default {} */\n props: AnyObject;\n\n /** If slots are used to modify the component, this will contain a reference to the original slots object. @default {} */\n slots: AnyObject;\n\n /** The exposed state of the component. @default {} */\n state: AnyObject;\n}\n\n/**\n * Checks if the given string is an event listener name. An event listener name\n * is defined as a string that starts with \"on\" followed by an uppercase letter.\n *\n * @param name - The string to check.\n * @returns `true` if the string is an event listener name, otherwise `false`.\n * @private\n */\nexport function isEventListener(name: string): boolean {\n return /^on[A-Z]/.test(name);\n}\n\n/**\n * Determines if a given value is a render prop.\n *\n * A render prop is a function that is used to dynamically generate\n * UI elements. This function checks if the provided value is a function\n * and not an event listener.\n *\n * @param name - The name of the prop.\n * @param value - The value of the prop to check.\n * @returns `true` if the value is a render prop, otherwise `false`.\n */\nexport function isRenderProp(name: string, value: any): boolean {\n return typeof value === 'function' && !isEventListener(name);\n}\n\n/**\n * Executes a function or returns a value from the given data object.\n *\n * @param name - The name of the property to execute or retrieve.\n * @param data - The data object containing the property.\n * @param args - The arguments to pass if the property is a function.\n * @returns The result of the function execution or the value of the property.\n * @private\n */\nexport function execute(name: string, data: AnyObject, args: RenderPropData): any {\n const value = data[name];\n\n if (isRenderProp(name, value)) return value(args);\n return value;\n}\n\n/**\n * Retrieves a property value, potentially overridden by a slotted value.\n *\n * @param name - The name of the property to retrieve.\n * @param options.props - The original properties.\n * @param options.slots - The slotted values that can override the original properties.\n * @param options.state - The current state.\n * @param options.original - The original value of the property.\n * @returns The original property value or the overridden value if provided.\n */\nexport function renderProp(name: string, args: RenderPropData): any {\n const { props, slots, original } = args;\n\n return execute(name, slots, args) || execute(name, props, args) || original;\n}\n\n/**\n * Merges multiple refs into a single ref callback.\n *\n * @param refs - Array of refs to merge (can include undefined/null).\n * @returns A single merged ref, undefined if no refs provided.\n * @private\n */\nfunction mergeRefList(refs: Array<ForwardedRef<any> | Ref<any> | undefined>): Ref<any> | undefined {\n const filtered = refs.filter((ref): ref is ForwardedRef<any> | Ref<any> => ref != null);\n\n if (!filtered.length) return undefined;\n if (filtered.length === 1) return filtered[0] as Ref<any>;\n\n return mergeRefs(...(filtered as Array<Ref<any>>)) as Ref<any>;\n}\n\nexport interface Returns {\n /**\n * Proxy object that have access to the original props, slotted values, and internal props. When\n * accessing a property, it will first check the slotted values, then the original props, and finally\n * the internal props. If the property is a render prop, it will execute the function with the provided\n * arguments.\n *\n * @default { ...props, ...slots }\n */\n props: AnyObject;\n /**\n * Applies the given attributes as default values to the props. If no attributes are provided, it will\n * use the props as default values. The resulting object will contain all the properties of the props,\n * except for the ones specified in the `except` array. The values of the properties will be the result\n * of executing the render prop function with the provided arguments.\n *\n * @default function(attr)\n */\n apply: (attributes?: object, except?: string[]) => object;\n /**\n * The merged ref combining forwarded refs with any ref supplied via slots.\n */\n ref?: Ref<any>;\n}\n\n/**\n * Hook that merges props with slotted props and provides a proxy for accessing them.\n *\n * @param args - The initial props to use, or array when using rest parameters.\n * @param state - The state object to use.\n * @param forwardedRef - The ref forwarded to the component.\n * @returns An object containing the proxy based props object and the apply function.\n * @throws {BentoError} If the hook is used outside of a @bento/slots component.\n *\n * @example\n * const { props, apply, ref } = useProps({ foo: 'bar' }, {}, forwardedRef);\n * if (props.a) doSomething()\n * return <a {...apply({ className: 'foo' }, ['ref']) } ref={ref}>{ props.children }</a>;\n *\n * @example\n * // With rest parameters\n * function Component(...rest) {\n * const { props, apply, ref } = useProps(rest);\n * return <div {...apply()} />;\n * }\n */\nexport function useProps(...rest: any[]): Returns {\n let forwardedRef: ForwardedRef<any> | undefined;\n let args: AnyObject;\n let state: object;\n\n if (Array.isArray(rest[0])) {\n [args, forwardedRef] = rest[0];\n state = rest[1];\n } else {\n [args, state, forwardedRef] = rest;\n }\n\n const { slots } = useContext<BoxContext<AnyObject>>(Box);\n const [props, internal] = useInternalProps(args);\n const { namespace, assigned } = slots;\n const dot = namespace.join('.');\n const slotted = assigned[dot] || {};\n\n const ref = mergeRefList([\n (props as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n (slotted as AnyObject)?.ref as ForwardedRef<any> | Ref<any> | undefined,\n forwardedRef\n ]);\n\n const slotNoRef = { ...slotted } as AnyObject;\n const propsNoRef = { ...props } as AnyObject;\n\n delete slotNoRef.ref;\n delete propsNoRef.ref;\n\n const propsy: AnyObject = { ...internal, ...propsNoRef, ...slotNoRef };\n\n /**\n * Applies the given attributes to an object.\n *\n * @param attributes - The attributes to apply. If not provided, defaults to `propsy`.\n * @param except - An array of keys to exclude from the resulting object.\n * @returns The resulting object with applied attributes.\n * @public\n */\n function apply(attributes?: object, except?: string[]): object {\n const data = (attributes || propsy) as AnyObject;\n const returned: AnyObject = {};\n\n function reduce(memo: AnyObject, key: string) {\n if (except && except.includes(key)) return memo;\n\n memo[key] = renderProp(key, {\n props: { ...props, ...internal },\n original: data[key],\n slots: slotted,\n state\n });\n\n return memo;\n }\n\n let result: AnyObject;\n\n if (!attributes) result = Object.keys(propsy).reduce(reduce, returned);\n else result = Object.keys(propsy).reduce(reduce, Object.keys(attributes).reduce(reduce, returned));\n\n // Always include the merged ref unless specifically excluded\n if (except && except.includes('ref')) return result;\n if (ref) result.ref = ref;\n\n return result;\n }\n\n return {\n props: new Proxy(propsy, {\n get: function getter(_: object, name: string) {\n if (name === 'ref') return ref;\n\n return renderProp(name, {\n original: isRenderProp(name, props[name]) ? undefined : props[name],\n props: { ...props, ...internal },\n slots: slotted,\n state\n });\n }\n }),\n apply,\n ref\n };\n}\n"]}