fetta 1.4.4 → 1.5.1

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Fetta
2
2
 
3
- A text-splitting library with kerning compensation for smooth, natural text animations.
3
+ Text splitting that keeps kerning intact.
4
4
 
5
5
  Split text into characters, words, and lines while preserving the original typography. Works with any animation library.
6
6
 
@@ -8,17 +8,17 @@ Split text into characters, words, and lines while preserving the original typog
8
8
 
9
9
  - **Kerning Compensation** — Maintains original character spacing when splitting by chars
10
10
  - **Nested Elements** — Preserves `<a>`, `<em>`, `<strong>` and other inline elements with all attributes
11
- - **Line Detection** — Automatically groups words into lines
11
+ - **Line Detection** — Groups words into rendered lines
12
12
  - **Dash Handling** — Allows text to wrap naturally after em-dashes, en-dashes, hyphens, and slashes
13
13
  - **Auto Re-split** — Re-splits on container resize
14
- - **Auto-Revert** — Restore original HTML after animations
14
+ - **Auto Revert** — Restores original HTML after animations
15
15
  - **Masking** — Wrap elements in clip containers for reveal animations
16
16
  - **Emoji Support** — Properly handles compound emojis and complex Unicode characters
17
17
  - **Accessible** — Automatic screen reader support, even when splitting text with nested links or emphasis
18
18
  - **TypeScript** — Full type definitions included
19
19
  - **React Component** — Declarative wrapper for React projects
20
- - **Built-in InView** — Viewport detection for scroll-triggered animations in React
21
- - **Library Agnostic** — Works with Motion, GSAP, or any animation library
20
+ - **Viewport Triggers** — Scroll enter/leave callbacks with configurable thresholds in React
21
+ - **Library Agnostic** — Works with Motion, GSAP, CSS, or any animation library
22
22
 
23
23
  ## Installation
24
24
 
@@ -26,7 +26,11 @@ Split text into characters, words, and lines while preserving the original typog
26
26
  npm install fetta
27
27
  ```
28
28
 
29
- **Bundle size**: ~3.9 kB (`fetta/core`) / ~4.8 kB (`fetta/react`) — minified + compressed
29
+ **Bundle size** (minified + brotli)
30
+ - `fetta`: ~7.17 kB
31
+ - `fetta/react`: ~8.66 kB
32
+ - `fetta/motion`: ~15.93 kB
33
+ - `fetta/helpers`: ~765 B
30
34
 
31
35
  ## Quick Start
32
36
 
@@ -83,13 +87,13 @@ const result = splitText(element, options);
83
87
  | `lineClass` | `string` | `"split-line"` | CSS class for line elements |
84
88
  | `mask` | `string` | — | Wrap elements in `overflow: clip` container: `"chars"`, `"words"`, or `"lines"` |
85
89
  | `autoSplit` | `boolean` | `false` | Re-split on container resize |
86
- | `onResize` | `function` | — | Callback after resize re-split |
87
- | `onSplit` | `function` | — | Callback after initial split |
90
+ | `onResplit` | `function` | — | Callback after autoSplit/full-resplit replaces split output elements |
91
+ | `onSplit` | `function` | — | Callback after initial split. Return animation/promise for `revertOnComplete` |
88
92
  | `revertOnComplete` | `boolean` | `false` | Auto-revert when animation completes |
89
93
  | `propIndex` | `boolean` | `false` | Add CSS custom properties: `--char-index`, `--word-index`, `--line-index` |
90
94
  | `disableKerning` | `boolean` | `false` | Skip kerning compensation (no margin adjustments) |
91
95
  | `initialStyles` | `object` | — | Apply initial inline styles to chars/words/lines after split. Values can be objects or `(el, index) => object` functions |
92
- | `initialClasses` | `object` | — | Apply initial CSS classes to chars/words/lines after split. Values can be strings or `(el, index) => string` functions |
96
+ | `initialClasses` | `object` | — | Apply initial CSS classes to chars/words/lines. Values are strings |
93
97
 
94
98
  #### Return Value
95
99
 
@@ -102,13 +106,57 @@ const result = splitText(element, options);
102
106
  }
103
107
  ```
104
108
 
109
+ ### `createSplitClones(splitResult, options)` (`fetta/helpers`)
110
+
111
+ Builds swap/reveal DOM layers (clones + optional wrappers) without coupling to any animation library.
112
+
113
+ ```ts
114
+ import { splitText } from "fetta";
115
+ import { createSplitClones } from "fetta/helpers";
116
+
117
+ const split = splitText(element, { type: "chars", mask: "chars" });
118
+ const layers = createSplitClones(split, { unit: "chars", wrap: true });
119
+
120
+ // Animate with Motion, GSAP, WAAPI, or CSS
121
+ // ...
122
+
123
+ layers.cleanup(); // removes clones/wrappers, keeps split DOM
124
+ // layers.cleanup({ revertSplit: true }) // also calls split.revert()
125
+ ```
126
+
127
+ #### Behavior
128
+
129
+ - Clone is always appended to the **current parent** of the original split node.
130
+ - `wrap: false` (default): clone is appended to existing parent (often the mask wrapper).
131
+ - `wrap: true`: original is first moved into a track wrapper, then clone is appended there.
132
+ - Helper never calls `splitText` and never performs animation.
133
+
134
+ #### Options
135
+
136
+ | Option | Type | Default | Description |
137
+ |--------|------|---------|-------------|
138
+ | `unit` | `"chars" \| "words" \| "lines"` | — | Which split nodes to layer |
139
+ | `wrap` | `boolean` | `false` | Wrap each original in a track wrapper (`position: relative`) |
140
+ | `display` | `"auto" \| "inline-block" \| "block"` | `"auto"` | Track display when `wrap: true` (`lines` => `block`, others => `inline-block`) |
141
+ | `cloneOffset.axis` | `"x" \| "y"` | `"y"` | Axis used for initial clone offset |
142
+ | `cloneOffset.direction` | `"start" \| "end"` | `"start"` | Offset direction (`start` => negative) |
143
+ | `cloneOffset.distance` | `string` | `"100%"` | Offset distance |
144
+ | `trackClassName` / `cloneClassName` | `string \| (ctx) => string \| undefined` | — | Class names (static or per-item) |
145
+ | `trackStyle` / `cloneStyle` | `object \| (ctx) => object` | — | Inline styles (static or per-item) |
146
+
147
+ For reveal/swap effects, use matching `mask` in `splitText` (`"chars"`, `"words"`, or `"lines"`).
148
+
105
149
  ### `<SplitText>` (React)
106
150
 
107
151
  ```tsx
108
152
  import { SplitText } from 'fetta/react';
109
153
  ```
110
154
 
111
- #### Props
155
+ `fetta/react` forwards common wrapper DOM props (`id`, `role`, `tabIndex`, `aria-*`, `data-*`, and event handlers like `onClick`) to the wrapper element.
156
+
157
+ `fetta/react` props:
158
+
159
+ #### React Props
112
160
 
113
161
  | Prop | Type | Default | Description |
114
162
  |------|------|---------|-------------|
@@ -117,21 +165,35 @@ import { SplitText } from 'fetta/react';
117
165
  | `className` | `string` | — | Class name for wrapper element |
118
166
  | `style` | `CSSProperties` | — | Additional styles for wrapper element |
119
167
  | `ref` | `Ref<HTMLElement>` | — | Ref to container element |
120
- | `onSplit` | `(result) => void` | — | Called after text is split |
121
- | `onResize` | `(result) => void` | — | Called on autoSplit re-split |
122
- | `options` | `SplitOptions` | — | Split options (type, classes, mask, propIndex, disableKerning) |
168
+ | `onSplit` | `(result) => CallbackReturn` | — | Called after text is split |
169
+ | `onResplit` | `(result) => void` | — | Called when autoSplit/full-resplit replaces split output elements |
170
+ | `options` | `SplitTextOptions` | — | Split options (type, classes, mask, propIndex, disableKerning) |
123
171
  | `autoSplit` | `boolean` | `false` | Re-split on container resize |
172
+ | `waitForFonts` | `boolean` | `true` | Wait for `document.fonts.ready` before splitting (recommended for stable kerning). Set `false` for immediate split. |
124
173
  | `revertOnComplete` | `boolean` | `false` | Revert after animation completes |
125
- | `inView` | `boolean \| InViewOptions` | `false` | Enable viewport detection |
126
- | `onInView` | `(result) => void` | — | Called when element enters viewport |
127
- | `onLeaveView` | `(result) => void` | — | Called when element leaves viewport |
174
+ | `onRevert` | `() => void` | | Called when split text is reverted (manual or automatic) |
175
+ | `viewport` | `ViewportOptions` | — | Configure viewport detection |
176
+ | `onViewportEnter` | `(result) => CallbackReturn` | — | Called when element enters viewport |
177
+ | `onViewportLeave` | `(result) => CallbackReturn` | — | Called when element leaves viewport |
128
178
  | `initialStyles` | `object` | — | Apply initial inline styles to chars/words/lines. Values can be objects or `(el, index) => object` functions |
129
- | `initialClasses` | `object` | — | Apply initial CSS classes to chars/words/lines. Values can be strings or `(el, index) => string` functions |
130
- | `resetOnLeave` | `boolean` | `false` | Re-apply initialStyles/initialClasses when leaving viewport |
179
+ | `initialClasses` | `object` | — | Apply initial CSS classes to chars/words/lines. Values are strings |
180
+ | `resetOnViewportLeave` | `boolean` | `false` | Re-apply initialStyles/initialClasses when leaving viewport |
181
+
182
+ #### Shared `SplitTextOptions` (`options` prop)
183
+
184
+ | Option | Type | Default | Description |
185
+ |------|------|---------|-------------|
186
+ | `type` | `SplitType` | `"chars,words,lines"` | What to split: `"chars"`, `"words"`, `"lines"`, or combinations |
187
+ | `charClass` | `string` | `"split-char"` | CSS class for character spans |
188
+ | `wordClass` | `string` | `"split-word"` | CSS class for word spans |
189
+ | `lineClass` | `string` | `"split-line"` | CSS class for line spans |
190
+ | `mask` | `"lines" \| "words" \| "chars"` | — | Wrap elements in `overflow: clip` mask containers |
191
+ | `propIndex` | `boolean` | `false` | Add CSS index variables (`--char-index`, `--word-index`, `--line-index`) |
192
+ | `disableKerning` | `boolean` | `false` | Skip kerning compensation (no margin adjustments) |
131
193
 
132
194
  #### Callback Signature
133
195
 
134
- All callbacks (`onSplit`, `onResize`, `onInView`, `onLeaveView`) receive the same result object:
196
+ All callbacks (`onSplit`, `onResplit`, `onViewportEnter`, `onViewportLeave`) receive:
135
197
 
136
198
  ```ts
137
199
  {
@@ -142,16 +204,85 @@ All callbacks (`onSplit`, `onResize`, `onInView`, `onLeaveView`) receive the sam
142
204
  }
143
205
  ```
144
206
 
145
- #### InView Options
207
+ ```ts
208
+ type CallbackReturn =
209
+ | void
210
+ | Promise<unknown>
211
+ | { finished: Promise<unknown> }
212
+ | { then: (onFulfilled?: ((result: unknown) => unknown) | undefined) => unknown }
213
+ | CallbackReturn[];
214
+ ```
215
+
216
+ When using `autoSplit` with `lines` in scroll-linked or scroll-triggered animations, re-attach scroll/timeline logic inside `onResplit` so it binds to the new split element references.
217
+
218
+ `onRevert` is a separate zero-argument callback that fires when a split cycle actually reverts.
219
+
220
+ #### Viewport Options
146
221
 
147
222
  ```ts
148
223
  {
149
- amount?: number; // How much must be visible (0-1), default: 0
150
- margin?: string; // Root margin, default: "0px"
151
- once?: boolean; // Only trigger once, default: false
224
+ amount?: number | "some" | "all"; // Enter threshold, default: 0
225
+ leave?: number | "some" | "all"; // Leave threshold, default: 0
226
+ margin?: string; // Root margin, default: "0px"
227
+ once?: boolean; // Only trigger once, default: false
228
+ root?: RefObject<Element>; // Optional root element
152
229
  }
153
230
  ```
154
231
 
232
+ ### `<SplitText>` (Motion)
233
+
234
+ ```tsx
235
+ import { SplitText } from "fetta/motion";
236
+ ```
237
+
238
+ `fetta/motion` includes all props from `fetta/react`, plus Motion variant props. It also forwards standard Motion/DOM wrapper props (`id`, `role`, `tabIndex`, `layout`, `drag`, `data-*`, etc.) to the wrapper.
239
+
240
+ Animate on exit with Motion's `AnimatePresence` (make `SplitText` the direct child):
241
+
242
+ ```tsx
243
+ import { AnimatePresence } from "motion/react";
244
+
245
+ <AnimatePresence>
246
+ {isVisible && (
247
+ <SplitText
248
+ variants={{
249
+ enter: { opacity: 1, y: 0 },
250
+ exit: { opacity: 0, y: 12 },
251
+ }}
252
+ initial="enter"
253
+ animate="enter"
254
+ exit="exit"
255
+ options={{ type: "words" }}
256
+ >
257
+ <h1>Goodbye</h1>
258
+ </SplitText>
259
+ )}
260
+ </AnimatePresence>
261
+ ```
262
+
263
+ #### Motion-only Props
264
+
265
+ | Prop | Type | Default | Description |
266
+ |------|------|---------|-------------|
267
+ | `variants` | `Record<string, VariantDefinition<TCustom>>` | — | Named variant definitions |
268
+ | `initial` | `string \| VariantDefinition<TCustom> \| false` | — | Initial variant applied instantly after split |
269
+ | `animate` | `string \| VariantDefinition<TCustom>` | — | Base variant |
270
+ | `exit` | `string \| VariantDefinition<TCustom> \| false` | — | Exit variant (AnimatePresence) |
271
+ | `whileInView` | `string \| VariantDefinition<TCustom>` | — | Variant while element is in view |
272
+ | `whileOutOfView` | `string \| VariantDefinition<TCustom>` | — | Variant after element leaves view |
273
+ | `whileScroll` | `string \| VariantDefinition<TCustom>` | — | Scroll-driven variant (highest trigger priority) |
274
+ | `whileHover` | `string \| VariantDefinition<TCustom>` | — | Variant on hover |
275
+ | `whileTap` | `string \| VariantDefinition<TCustom>` | — | Variant on tap/press |
276
+ | `whileFocus` | `string \| VariantDefinition<TCustom>` | — | Variant on focus |
277
+ | `animateOnResplit` | `boolean` | `false` | Replay initial->animate on autoSplit/full-resplit |
278
+ | `scroll` | `{ offset?, axis?, container? }` | — | Scroll tracking options for `whileScroll` |
279
+ | `transition` | `AnimationOptions` | — | Global/default transition for variants |
280
+ | `custom` | `TCustom` | — | Custom data forwarded to function variants |
281
+ | `delayScope` | `"global" \| "local"` | `"global"` | Delay-function index scope (`globalIndex` vs relative `index`) |
282
+ | `reducedMotion` | `"user" \| "always" \| "never"` | — | Reduced-motion behavior for this component |
283
+ | `onHoverStart` | `() => void` | — | Called when hover starts |
284
+ | `onHoverEnd` | `() => void` | — | Called when hover ends |
285
+
155
286
  ## Examples
156
287
 
157
288
  ### Vanilla JavaScript
@@ -243,7 +374,7 @@ splitText(element, { type: 'chars', propIndex: true });
243
374
  </SplitText>
244
375
  ```
245
376
 
246
- #### Scroll-Triggered with InView
377
+ #### Scroll-Triggered with Viewport
247
378
 
248
379
  ```tsx
249
380
  <SplitText
@@ -251,11 +382,11 @@ splitText(element, { type: 'chars', propIndex: true });
251
382
  initialStyles={{
252
383
  words: { opacity: '0', transform: 'translateY(20px)' }
253
384
  }}
254
- inView={{ amount: 0.5 }}
255
- onInView={({ words }) => {
385
+ viewport={{ amount: 0.5 }}
386
+ onViewportEnter={({ words }) => {
256
387
  animate(words, { opacity: 1, y: 0 }, { delay: stagger(0.03) });
257
388
  }}
258
- resetOnLeave
389
+ resetOnViewportLeave
259
390
  >
260
391
  <p>Animates when scrolled into view</p>
261
392
  </SplitText>
@@ -274,6 +405,104 @@ splitText(element, { type: 'chars', propIndex: true });
274
405
  </SplitText>
275
406
  ```
276
407
 
408
+ ### Motion (`fetta/motion`)
409
+
410
+ #### Basic Variants
411
+
412
+ ```tsx
413
+ import { SplitText } from 'fetta/motion';
414
+ import { stagger } from 'motion';
415
+
416
+ <SplitText
417
+ variants={{
418
+ hidden: { opacity: 0, y: 20, filter: 'blur(6px)' },
419
+ visible: { opacity: 1, y: 0, filter: 'blur(0px)' },
420
+ }}
421
+ initial="hidden"
422
+ animate="visible"
423
+ transition={{ duration: 0.6, delay: stagger(0.04) }}
424
+ options={{ type: 'words' }}
425
+ >
426
+ <h1>Hello World</h1>
427
+ </SplitText>
428
+ ```
429
+
430
+ #### Line-Aware Stagger
431
+
432
+ ```tsx
433
+ import { SplitText } from 'fetta/motion';
434
+ import { stagger } from 'motion';
435
+
436
+ <SplitText
437
+ delayScope="local"
438
+ variants={{
439
+ hidden: { chars: { opacity: 0 } },
440
+ visible: {
441
+ chars: ({ lineIndex }) => ({
442
+ opacity: 1,
443
+ transition: {
444
+ duration: 0.3,
445
+ delay: stagger(0.015, {
446
+ startDelay: lineIndex * 0.2,
447
+ from: lineIndex % 2 === 0 ? "first" : "last",
448
+ }),
449
+ },
450
+ }),
451
+ },
452
+ }}
453
+ initial="hidden"
454
+ animate="visible"
455
+ options={{ type: "chars,lines" }}
456
+ >
457
+ <p>Line-aware per-character animation</p>
458
+ </SplitText>
459
+ ```
460
+
461
+ #### Scroll-Driven Reveal
462
+
463
+ ```tsx
464
+ import { SplitText } from 'fetta/motion';
465
+
466
+ <SplitText
467
+ initialStyles={{ chars: { opacity: 0.2 } }}
468
+ whileScroll={{
469
+ chars: ({ globalIndex }) => ({
470
+ opacity: 1,
471
+ transition: {
472
+ duration: 0.3,
473
+ at: globalIndex * 0.025,
474
+ ease: "linear",
475
+ },
476
+ }),
477
+ }}
478
+ scroll={{ offset: ["start 90%", "start 10%"] }}
479
+ options={{ type: "chars" }}
480
+ >
481
+ <p>Characters fade in with scroll progress</p>
482
+ </SplitText>
483
+ ```
484
+
485
+ #### Hover Interaction
486
+
487
+ ```tsx
488
+ import { SplitText } from 'fetta/motion';
489
+ import { stagger } from 'motion';
490
+
491
+ <SplitText
492
+ variants={{
493
+ rest: { chars: { opacity: 0.85, y: 0 } },
494
+ hover: { chars: { opacity: 1, y: -6 } },
495
+ }}
496
+ initial="rest"
497
+ animate="rest"
498
+ whileHover="hover"
499
+ transition={{ duration: 0.25, delay: stagger(0.01) }}
500
+ options={{ type: 'chars' }}
501
+ >
502
+ <p>Hover this text</p>
503
+ </SplitText>
504
+ ```
505
+
277
506
  ## CSS Classes
278
507
 
279
508
  Default classes applied to split elements:
@@ -284,7 +513,10 @@ Default classes applied to split elements:
284
513
  | `.split-word` | Words | Inline positioning |
285
514
  | `.split-line` | Lines | Block display |
286
515
 
287
- Each element also receives a `data-index` attribute with its position.
516
+ Split elements receive typed index attributes:
517
+ - Characters: `data-char-index`
518
+ - Words: `data-word-index`
519
+ - Lines: `data-line-index`
288
520
 
289
521
  ## Font Loading
290
522
 
@@ -297,7 +529,17 @@ document.fonts.ready.then(() => {
297
529
  });
298
530
  ```
299
531
 
300
- The React component handles this automatically no additional setup required.
532
+ React and Motion components wait for fonts by default (`waitForFonts={true}`), which gives the most stable kerning.
533
+
534
+ If you notice a visual shift after splitting, keep the default waiting behavior enabled.
535
+
536
+ If you need immediate splitting (for example, responsiveness-first UI), you can opt out with `waitForFonts={false}`:
537
+
538
+ ```tsx
539
+ <SplitText waitForFonts={false}>
540
+ <h1>Split Immediately</h1>
541
+ </SplitText>
542
+ ```
301
543
 
302
544
  ## Accessibility
303
545
 
@@ -332,6 +574,7 @@ Pre-existing `aria-label` attributes are always preserved.
332
574
  ## Notes
333
575
 
334
576
  - **Ligatures are disabled** (`font-variant-ligatures: none`) because ligatures cannot span multiple elements.
577
+ - **Authored hard breaks are preserved** — Explicit `<br>` and block-level descendants are treated as hard boundaries. In `chars`/`words` modes, hard boundaries are normalized to `<br>` in the split output.
335
578
 
336
579
  ## Browser Support
337
580
 
@@ -0,0 +1,43 @@
1
+ // src/internal/initialStyles.ts
2
+ function reapplyInitialStyles(elements, style) {
3
+ if (!style || elements.length === 0) return;
4
+ const isFn = typeof style === "function";
5
+ for (let i = 0; i < elements.length; i++) {
6
+ const el = elements[i];
7
+ const styles = isFn ? style(el, i) : style;
8
+ for (const [key, value] of Object.entries(styles)) {
9
+ if (value == null) continue;
10
+ if (key === "cssText") {
11
+ if (typeof value === "string") {
12
+ el.style.cssText = value;
13
+ }
14
+ continue;
15
+ }
16
+ if (typeof value !== "string" && typeof value !== "number") continue;
17
+ const cssValue = typeof value === "number" ? String(value) : value;
18
+ const cssKey = key.startsWith("--") ? key : key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
19
+ el.style.setProperty(cssKey, cssValue);
20
+ }
21
+ }
22
+ }
23
+ function reapplyInitialClasses(elements, className) {
24
+ if (!className || elements.length === 0) return;
25
+ const classes = className.split(/\s+/).filter(Boolean);
26
+ for (const el of elements) {
27
+ el.classList.add(...classes);
28
+ }
29
+ }
30
+
31
+ // src/internal/waitForFontsReady.ts
32
+ async function waitForFontsReady(waitForFonts) {
33
+ if (!waitForFonts) return;
34
+ const fonts = document.fonts;
35
+ const ready = fonts == null ? void 0 : fonts.ready;
36
+ if (!ready || typeof ready.then !== "function") return;
37
+ try {
38
+ await ready;
39
+ } catch (e) {
40
+ }
41
+ }
42
+
43
+ export { reapplyInitialClasses, reapplyInitialStyles, waitForFontsReady };
@@ -0,0 +1,33 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
32
+
33
+ export { __objRest, __spreadProps, __spreadValues };