@destyler/tabs 0.2.10 → 0.2.12

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.d.mts CHANGED
@@ -1,14 +1,11 @@
1
- import * as _destyler_anatomy0 from "@destyler/anatomy";
2
- import * as _destyler_xstate0 from "@destyler/xstate";
3
1
  import { AnyEventObject, Machine, XSend, XState } from "@destyler/xstate";
4
2
  import { CommonProperties, DirectionProperty, NormalizeProps, PropTypes, RequiredBy } from "@destyler/types";
5
-
6
3
  //#region src/anatomy.d.ts
7
- declare const anatomy: _destyler_anatomy0.AnatomyInstance<"root" | "list" | "trigger" | "content" | "indicator">;
4
+ export declare const anatomy: import("@destyler/anatomy").AnatomyInstance<"root" | "list" | "trigger" | "content" | "indicator">;
8
5
  //#endregion
9
6
  //#region src/types.d.ts
10
7
  interface ValueChangeDetails {
11
- value: string;
8
+ value: string | null;
12
9
  }
13
10
  interface FocusChangeDetails {
14
11
  focusedValue: string;
@@ -209,17 +206,17 @@ interface MachineApi<T extends PropTypes = PropTypes> {
209
206
  }
210
207
  //#endregion
211
208
  //#region src/connect.d.ts
212
- declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T>;
209
+ export declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T>;
213
210
  //#endregion
214
211
  //#region src/machine.d.ts
215
- declare function machine(userContext: UserDefinedContext): _destyler_xstate0.Machine<MachineContext, MachineState, _destyler_xstate0.AnyEventObject>;
212
+ export declare function machine(userContext: UserDefinedContext): import("@destyler/xstate").Machine<MachineContext, MachineState, import("@destyler/xstate").AnyEventObject>;
216
213
  //#endregion
217
214
  //#region src/props.d.ts
218
- declare const props: ("value" | "ids" | "translations" | "loopFocus" | "defaultValue" | "orientation" | "activationMode" | "onValueChange" | "onFocusChange" | "composite" | "deselectable" | "navigate" | "dir" | "id" | "getRootNode")[];
219
- declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "value" | "ids" | "translations" | "loopFocus" | "defaultValue" | "orientation" | "activationMode" | "onValueChange" | "onFocusChange" | "composite" | "deselectable" | "navigate" | "dir" | "id" | "getRootNode">];
220
- declare const triggerProps: (keyof TriggerProps)[];
221
- declare const splitTriggerProps: <Props extends TriggerProps>(props: Props) => [TriggerProps, Omit<Props, keyof TriggerProps>];
222
- declare const contentProps: "value"[];
223
- declare const splitContentProps: <Props extends ContentProps>(props: Props) => [ContentProps, Omit<Props, "value">];
215
+ export declare const props: ("value" | "ids" | "translations" | "loopFocus" | "defaultValue" | "orientation" | "activationMode" | "onValueChange" | "onFocusChange" | "composite" | "deselectable" | "navigate" | "dir" | "id" | "getRootNode")[];
216
+ export declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "value" | "ids" | "translations" | "loopFocus" | "defaultValue" | "orientation" | "activationMode" | "onValueChange" | "onFocusChange" | "composite" | "deselectable" | "navigate" | "dir" | "id" | "getRootNode">];
217
+ export declare const triggerProps: (keyof TriggerProps)[];
218
+ export declare const splitTriggerProps: <Props extends TriggerProps>(props: Props) => [TriggerProps, Omit<Props, keyof TriggerProps>];
219
+ export declare const contentProps: "value"[];
220
+ export declare const splitContentProps: <Props extends ContentProps>(props: Props) => [ContentProps, Omit<Props, "value">];
224
221
  //#endregion
225
- export { type MachineApi as Api, type ContentProps, type UserDefinedContext as Context, type ElementIds, type FocusChangeDetails, type IntlTranslations, type Service, type TriggerProps, type ValueChangeDetails, anatomy, connect, contentProps, machine, props, splitContentProps, splitProps, splitTriggerProps, triggerProps };
222
+ export type { MachineApi as Api, ContentProps, UserDefinedContext as Context, ElementIds, FocusChangeDetails, IntlTranslations, Service, TriggerProps, ValueChangeDetails };
package/dist/index.mjs CHANGED
@@ -4,11 +4,9 @@ import { compact, createSplitProps, first, isControlled, isEqual, isPropUserProv
4
4
  import { trackElementRect } from "@destyler/element-rect";
5
5
  import { createMachine, guards } from "@destyler/xstate";
6
6
  import { createProps } from "@destyler/types";
7
-
8
7
  //#region src/anatomy.ts
9
8
  const anatomy = createAnatomy("tabs").parts("root", "list", "trigger", "content", "indicator");
10
9
  const parts = anatomy.build();
11
-
12
10
  //#endregion
13
11
  //#region src/dom.ts
14
12
  const dom = createScope({
@@ -30,11 +28,11 @@ const dom = createScope({
30
28
  getNextTriggerEl: (ctx, id) => nextById(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
31
29
  getPrevTriggerEl: (ctx, id) => prevById(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
32
30
  getSelectedContentEl: (ctx) => {
33
- if (!ctx.value) return;
31
+ if (ctx.value == null) return;
34
32
  return dom.getContentEl(ctx, ctx.value);
35
33
  },
36
34
  getSelectedTriggerEl: (ctx) => {
37
- if (!ctx.value) return;
35
+ if (ctx.value == null) return;
38
36
  return dom.getTriggerEl(ctx, ctx.value);
39
37
  },
40
38
  getOffsetRect: (el) => {
@@ -56,7 +54,6 @@ const dom = createScope({
56
54
  top: `${rect.top}px`
57
55
  })
58
56
  });
59
-
60
57
  //#endregion
61
58
  //#region src/connect.ts
62
59
  function connect(state, send, normalize) {
@@ -66,11 +63,11 @@ function connect(state, send, normalize) {
66
63
  const isHorizontal = state.context.orientation === "horizontal";
67
64
  const composite = state.context.composite;
68
65
  const indicator = state.context.indicatorState;
69
- function getTriggerState(props$1) {
66
+ function getTriggerState(props) {
70
67
  return {
71
- selected: state.context.value === props$1.value,
72
- focused: state.context.focusedValue === props$1.value,
73
- disabled: !!props$1.disabled
68
+ selected: state.context.value === props.value,
69
+ focused: state.context.focusedValue === props.value,
70
+ disabled: !!props.disabled
74
71
  };
75
72
  }
76
73
  return {
@@ -88,7 +85,7 @@ function connect(state, send, normalize) {
88
85
  setIndicatorRect(value) {
89
86
  send({
90
87
  type: "SET_INDICATOR_RECT",
91
- id: dom.getTriggerId(state.context, value)
88
+ id: value
92
89
  });
93
90
  },
94
91
  syncTabIndex() {
@@ -142,7 +139,7 @@ function connect(state, send, normalize) {
142
139
  if (event.defaultPrevented) return;
143
140
  if (!isSelfTarget(event)) return;
144
141
  if (isComposingEvent(event)) return;
145
- const exec = {
142
+ const keyMap = {
146
143
  ArrowDown() {
147
144
  if (isHorizontal) return;
148
145
  send({
@@ -180,7 +177,11 @@ function connect(state, send, normalize) {
180
177
  Enter() {
181
178
  send({ type: "ENTER" });
182
179
  }
183
- }[getEventKey(event, state.context)];
180
+ };
181
+ const key = getEventKey(event, state.context);
182
+ if (isHorizontal && (key === "ArrowUp" || key === "ArrowDown")) return;
183
+ if (isVertical && (key === "ArrowLeft" || key === "ArrowRight")) return;
184
+ const exec = keyMap[key];
184
185
  if (exec) {
185
186
  event.preventDefault();
186
187
  exec(event);
@@ -189,9 +190,9 @@ function connect(state, send, normalize) {
189
190
  });
190
191
  },
191
192
  getTriggerState,
192
- getTriggerProps(props$1) {
193
- const { value, disabled } = props$1;
194
- const triggerState = getTriggerState(props$1);
193
+ getTriggerProps(props) {
194
+ const { value, disabled } = props;
195
+ const triggerState = getTriggerState(props);
195
196
  return normalize.button({
196
197
  ...parts.trigger.attrs,
197
198
  "role": "tab",
@@ -230,8 +231,8 @@ function connect(state, send, normalize) {
230
231
  }
231
232
  });
232
233
  },
233
- getContentProps(props$1) {
234
- const { value } = props$1;
234
+ getContentProps(props) {
235
+ const { value } = props;
235
236
  const selected = state.context.value === value;
236
237
  return normalize.element({
237
238
  ...parts.content.attrs,
@@ -269,13 +270,30 @@ function connect(state, send, normalize) {
269
270
  }
270
271
  };
271
272
  }
272
-
273
273
  //#endregion
274
274
  //#region src/machine.ts
275
275
  const { not } = guards;
276
+ const scheduledEffects = /* @__PURE__ */ new WeakMap();
277
+ function trackScheduledEffects(ctx) {
278
+ const pending = /* @__PURE__ */ new Set();
279
+ scheduledEffects.set(ctx, pending);
280
+ return () => {
281
+ if (scheduledEffects.get(ctx) === pending) scheduledEffects.delete(ctx);
282
+ pending.forEach((cleanup) => cleanup());
283
+ pending.clear();
284
+ };
285
+ }
286
+ function scheduleEffect(ctx, callback, schedule = raf) {
287
+ const pending = scheduledEffects.get(ctx);
288
+ if (!pending) return;
289
+ const cleanup = schedule(() => {
290
+ pending.delete(cleanup);
291
+ if (scheduledEffects.get(ctx) === pending) callback();
292
+ });
293
+ pending.add(cleanup);
294
+ }
276
295
  const invoke = {
277
296
  change: (ctx, value) => {
278
- if (value == null) return;
279
297
  ctx.onValueChange?.({ value });
280
298
  },
281
299
  focusChange: (ctx) => {
@@ -350,6 +368,7 @@ function machine(userContext) {
350
368
  SYNC_TAB_INDEX: { actions: "syncTabIndex" }
351
369
  },
352
370
  created: ["syncFocusedValue"],
371
+ activities: [trackScheduledEffects],
353
372
  entry: [
354
373
  "checkRenderedElements",
355
374
  "syncIndicatorRect",
@@ -401,116 +420,115 @@ function machine(userContext) {
401
420
  } }
402
421
  }
403
422
  }, {
404
- guards: { selectOnFocus: (ctx$1) => ctx$1.activationMode === "automatic" },
423
+ guards: { selectOnFocus: (ctx) => ctx.activationMode === "automatic" },
405
424
  actions: {
406
- syncFocusedValue(ctx$1) {
407
- if (ctx$1.value != null && ctx$1.focusedValue == null) ctx$1.focusedValue = ctx$1.value;
425
+ syncFocusedValue(ctx) {
426
+ if (ctx.value != null && ctx.focusedValue == null) ctx.focusedValue = ctx.value;
408
427
  },
409
- selectFocusedTab(ctx$1) {
410
- raf(() => {
411
- const value = ctx$1.deselectable && ctx$1.value === ctx$1.focusedValue ? null : ctx$1.focusedValue;
412
- set.value(ctx$1, value);
428
+ selectFocusedTab(ctx) {
429
+ scheduleEffect(ctx, () => {
430
+ const value = ctx.deselectable && ctx.value === ctx.focusedValue ? null : ctx.focusedValue;
431
+ set.value(ctx, value);
413
432
  });
414
433
  },
415
- setFocusedValue(ctx$1, evt) {
434
+ setFocusedValue(ctx, evt) {
416
435
  if (evt.value == null) return;
417
- set.focusedValue(ctx$1, evt.value);
436
+ set.focusedValue(ctx, evt.value);
418
437
  },
419
- clearFocusedValue(ctx$1) {
420
- set.focusedValue(ctx$1, null);
438
+ clearFocusedValue(ctx) {
439
+ set.focusedValue(ctx, null);
421
440
  },
422
- setValue(ctx$1, evt) {
423
- const value = ctx$1.deselectable && ctx$1.value === ctx$1.focusedValue ? null : evt.value;
424
- set.value(ctx$1, value);
441
+ setValue(ctx, evt) {
442
+ const value = ctx.deselectable && evt.type === "TAB_CLICK" && ctx.value === evt.value ? null : evt.value;
443
+ set.value(ctx, value);
425
444
  },
426
- clearValue(ctx$1) {
427
- set.value(ctx$1, null);
445
+ clearValue(ctx) {
446
+ set.value(ctx, null);
428
447
  },
429
- focusFirstTab(ctx$1) {
430
- raf(() => {
431
- dom.getFirstTriggerEl(ctx$1)?.focus();
448
+ focusFirstTab(ctx) {
449
+ scheduleEffect(ctx, () => {
450
+ dom.getFirstTriggerEl(ctx)?.focus();
432
451
  });
433
452
  },
434
- focusLastTab(ctx$1) {
435
- raf(() => {
436
- dom.getLastTriggerEl(ctx$1)?.focus();
453
+ focusLastTab(ctx) {
454
+ scheduleEffect(ctx, () => {
455
+ dom.getLastTriggerEl(ctx)?.focus();
437
456
  });
438
457
  },
439
- focusNextTab(ctx$1) {
440
- if (!ctx$1.focusedValue) return;
441
- const triggerEl = dom.getNextTriggerEl(ctx$1, ctx$1.focusedValue);
442
- raf(() => {
443
- if (ctx$1.composite) triggerEl?.focus();
444
- else if (triggerEl?.dataset.value != null) set.focusedValue(ctx$1, triggerEl.dataset.value);
458
+ focusNextTab(ctx) {
459
+ if (ctx.focusedValue == null) return;
460
+ const triggerEl = dom.getNextTriggerEl(ctx, ctx.focusedValue);
461
+ scheduleEffect(ctx, () => {
462
+ if (ctx.composite) triggerEl?.focus();
463
+ else if (triggerEl?.dataset.value != null) set.focusedValue(ctx, triggerEl.dataset.value);
445
464
  });
446
465
  },
447
- focusPrevTab(ctx$1) {
448
- if (!ctx$1.focusedValue) return;
449
- const triggerEl = dom.getPrevTriggerEl(ctx$1, ctx$1.focusedValue);
450
- raf(() => {
451
- if (ctx$1.composite) triggerEl?.focus();
452
- else if (triggerEl?.dataset.value != null) set.focusedValue(ctx$1, triggerEl.dataset.value);
466
+ focusPrevTab(ctx) {
467
+ if (ctx.focusedValue == null) return;
468
+ const triggerEl = dom.getPrevTriggerEl(ctx, ctx.focusedValue);
469
+ scheduleEffect(ctx, () => {
470
+ if (ctx.composite) triggerEl?.focus();
471
+ else if (triggerEl?.dataset.value != null) set.focusedValue(ctx, triggerEl.dataset.value);
453
472
  });
454
473
  },
455
- checkRenderedElements(ctx$1) {
456
- ctx$1.indicatorState.rendered = !!dom.getIndicatorEl(ctx$1);
474
+ checkRenderedElements(ctx) {
475
+ ctx.indicatorState.rendered = !!dom.getIndicatorEl(ctx);
457
476
  },
458
- syncTabIndex(ctx$1) {
459
- raf(() => {
460
- const contentEl = dom.getSelectedContentEl(ctx$1);
477
+ syncTabIndex(ctx) {
478
+ scheduleEffect(ctx, () => {
479
+ const contentEl = dom.getSelectedContentEl(ctx);
461
480
  if (!contentEl) return;
462
481
  if (getFocusables(contentEl).length > 0) contentEl.removeAttribute("tabindex");
463
482
  else contentEl.setAttribute("tabindex", "0");
464
483
  });
465
484
  },
466
- cleanupObserver(ctx$1) {
467
- ctx$1.indicatorCleanup?.();
485
+ cleanupObserver(ctx) {
486
+ ctx.indicatorCleanup?.();
468
487
  },
469
- allowIndicatorTransition(ctx$1) {
470
- ctx$1.indicatorState.transition = true;
488
+ allowIndicatorTransition(ctx) {
489
+ ctx.indicatorState.transition = true;
471
490
  },
472
- setIndicatorRect(ctx$1, evt) {
473
- const value = evt.id ?? ctx$1.value;
474
- if (!ctx$1.indicatorState.rendered || !value) return;
475
- if (!dom.getTriggerEl(ctx$1, value)) return;
476
- ctx$1.indicatorState.rect = dom.getRectById(ctx$1, value);
477
- nextTick(() => {
478
- ctx$1.indicatorState.transition = false;
479
- });
491
+ setIndicatorRect(ctx, evt) {
492
+ const value = evt.id ?? ctx.value;
493
+ if (!ctx.indicatorState.rendered || value == null) return;
494
+ if (!dom.getTriggerEl(ctx, value)) return;
495
+ ctx.indicatorState.rect = dom.getRectById(ctx, value);
496
+ scheduleEffect(ctx, () => {
497
+ ctx.indicatorState.transition = false;
498
+ }, nextTick);
480
499
  },
481
- syncSsr(ctx$1) {
482
- ctx$1.ssr = false;
500
+ syncSsr(ctx) {
501
+ ctx.ssr = false;
483
502
  },
484
- syncIndicatorRect(ctx$1) {
485
- ctx$1.indicatorCleanup?.();
486
- const value = ctx$1.value;
487
- if (!ctx$1.indicatorState.rendered || !value) return;
488
- const triggerEl = dom.getSelectedTriggerEl(ctx$1);
503
+ syncIndicatorRect(ctx) {
504
+ ctx.indicatorCleanup?.();
505
+ const value = ctx.value;
506
+ if (!ctx.indicatorState.rendered || value == null) return;
507
+ const triggerEl = dom.getSelectedTriggerEl(ctx);
489
508
  if (!triggerEl) return;
490
- ctx$1.indicatorCleanup = trackElementRect(triggerEl, {
509
+ ctx.indicatorCleanup = trackElementRect(triggerEl, {
491
510
  getRect(el) {
492
511
  return dom.getOffsetRect(el);
493
512
  },
494
513
  onChange(rect) {
495
- ctx$1.indicatorState.rect = dom.resolveRect(rect);
496
- nextTick(() => {
497
- ctx$1.indicatorState.transition = false;
498
- });
514
+ ctx.indicatorState.rect = dom.resolveRect(rect);
515
+ scheduleEffect(ctx, () => {
516
+ ctx.indicatorState.transition = false;
517
+ }, nextTick);
499
518
  }
500
519
  });
501
520
  },
502
- navigateIfNeeded(ctx$1) {
503
- const triggerEl = dom.getSelectedTriggerEl(ctx$1);
521
+ navigateIfNeeded(ctx) {
522
+ const triggerEl = dom.getSelectedTriggerEl(ctx);
504
523
  if (!isAnchorElement(triggerEl)) return;
505
- ctx$1.navigate({
506
- value: ctx$1.value,
524
+ ctx.navigate({
525
+ value: ctx.value,
507
526
  node: triggerEl
508
527
  });
509
528
  }
510
529
  }
511
530
  });
512
531
  }
513
-
514
532
  //#endregion
515
533
  //#region src/props.ts
516
534
  const props = createProps()([
@@ -535,6 +553,5 @@ const triggerProps = createProps()(["disabled", "value"]);
535
553
  const splitTriggerProps = createSplitProps(triggerProps);
536
554
  const contentProps = createProps()(["value"]);
537
555
  const splitContentProps = createSplitProps(contentProps);
538
-
539
556
  //#endregion
540
- export { anatomy, connect, contentProps, machine, props, splitContentProps, splitProps, splitTriggerProps, triggerProps };
557
+ export { anatomy, connect, contentProps, machine, props, splitContentProps, splitProps, splitTriggerProps, triggerProps };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@destyler/tabs",
3
3
  "type": "module",
4
- "version": "0.2.10",
4
+ "version": "0.2.12",
5
5
  "description": "A set of layered sections of content—known as tab panels—that are displayed one at a time.",
6
6
  "author": "Elone Hoo <elonehoo@gmail.com>",
7
7
  "license": "MIT",
@@ -22,12 +22,12 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@destyler/anatomy": "0.2.10",
26
- "@destyler/dom": "0.2.10",
27
- "@destyler/types": "0.2.10",
28
- "@destyler/element-rect": "0.2.10",
29
- "@destyler/utils": "0.2.10",
30
- "@destyler/xstate": "0.2.10"
25
+ "@destyler/anatomy": "0.2.12",
26
+ "@destyler/dom": "0.2.12",
27
+ "@destyler/element-rect": "0.2.12",
28
+ "@destyler/types": "0.2.12",
29
+ "@destyler/utils": "0.2.12",
30
+ "@destyler/xstate": "0.2.12"
31
31
  },
32
32
  "publishConfig": {
33
33
  "access": "public"