@kanso-labs/react-native-kanso-ui 0.3.1 → 0.4.0

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.
@@ -0,0 +1 @@
1
+ import "react-native";
@@ -1 +1 @@
1
- {"version":3,"file":"slots.js","names":["GestureResponderEvent","createContext","ButtonSlots","close","event","default","ButtonSlotContext"],"sources":["../../src/button/slots.ts"],"sourcesContent":["import type { GestureResponderEvent } from 'react-native'\n\nimport { createContext } from 'react'\n\n/**\n * What a button does past its own press when it sits in an overlay's trigger\n * or content, as web's React Aria hands the same through a button's `slot`:\n * the default slot opens the overlay, which a button inside `Dialog` and\n * outside its content takes, and `close` closes it, which one given\n * `slot=\"close\"` inside the content takes. The overlay provides the slots it\n * fills, and resets the default one inside its content, so a button there\n * opens nothing.\n */\ntype ButtonSlots = {\n readonly close?: (event: GestureResponderEvent) => void\n readonly default?: (event: GestureResponderEvent) => void\n}\n\nconst ButtonSlotContext = createContext<ButtonSlots | null>(null)\n\nexport { ButtonSlotContext }\nexport type { ButtonSlots }\n"],"mappings":";;AAkBA,MAAMM,oBAAoBL,cAAkC,IAAI"}
1
+ {"version":3,"file":"slots.js","names":["GestureResponderEvent","createContext","ButtonSlots","close","event","default","ButtonSlotContext"],"sources":["../../src/button/slots.ts"],"sourcesContent":["import type { GestureResponderEvent } from 'react-native'\n\nimport { createContext } from 'react'\n\n/**\n * What a button does past its own press when it sits in an overlay's trigger\n * or content, as web's React Aria hands the same through a button's `slot`:\n * the default slot opens the overlay, which a button inside `Dialog` or\n * `Sheet` and outside its content takes, and `close` closes it, which one\n * given `slot=\"close\"` inside the content takes. The overlay provides the\n * slots it fills, and resets the default one inside its content, so a button\n * there opens nothing.\n */\ntype ButtonSlots = {\n readonly close?: (event: GestureResponderEvent) => void\n readonly default?: (event: GestureResponderEvent) => void\n}\n\nconst ButtonSlotContext = createContext<ButtonSlots | null>(null)\n\nexport { ButtonSlotContext }\nexport type { ButtonSlots }\n"],"mappings":";;AAkBA,MAAMM,oBAAoBL,cAAkC,IAAI"}
@@ -1,3 +1,4 @@
1
+ import { ModalOpenProps } from "../../modal/index.js";
1
2
  import { HostInstance, ScrollView, ScrollViewProps, StyleProp, TextProps, View, ViewProps, ViewStyle } from "react-native";
2
3
  import { ComponentRef, ReactNode, Ref } from "react";
3
4
  //#region src/components/dialog/index.d.ts
@@ -31,7 +32,7 @@ type DialogContentProps = DialogOpenProps & Omit<ViewProps, 'children' | 'role'
31
32
  readonly role?: 'alertdialog' | 'dialog';
32
33
  readonly style?: StyleProp<ViewStyle>;
33
34
  };
34
- type DialogOpenProps = {
35
+ type DialogOpenProps = ModalOpenProps & {
35
36
  /** Whether the dialog starts open, when it keeps its own state. */
36
37
  readonly defaultOpen?: boolean;
37
38
  /** Whether the dialog is open, when the call site holds the state. */
@@ -2,36 +2,19 @@ import { useTheme } from "../../theme/scope.js";
2
2
  import { composeStyles, themedStyles } from "../../theme/styles.js";
3
3
  import { useTypeRole } from "../../typography/roles.js";
4
4
  import { ButtonSlotContext } from "../../button/slots.js";
5
- import { AnimatedPressable } from "../../button/index.js";
6
- import { withOpacity } from "../../theme/color.js";
7
5
  import { useWindowSizeClass } from "../../hooks/useWindowSizeClass.js";
8
- import { OverlayHost } from "../../overlay/host.js";
6
+ import { ModalWindow, NO_INSETS, insetsOf, panelRoleOf, refsOf, registerOf, useModalState, useModalTrigger } from "../../modal/index.js";
9
7
  import { c } from "react/compiler-runtime";
10
- import { AccessibilityInfo, Modal, Platform, ScrollView, StyleSheet, Text, View, useWindowDimensions } from "react-native";
11
- import { createContext, use, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
12
- import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { ScrollView, StyleSheet, Text, View, useWindowDimensions } from "react-native";
9
+ import { createContext, use, useEffect, useId, useLayoutEffect, useState } from "react";
10
+ import { jsx } from "react/jsx-runtime";
13
11
  import Animated, { Easing, useAnimatedStyle, useReducedMotion, useSharedValue, withTiming } from "react-native-reanimated";
14
12
  import { SafeAreaInsetsContext } from "react-native-safe-area-context";
15
- import { useOverlayTriggerState } from "react-stately/useOverlayTriggerState";
16
13
  //#region src/components/dialog/index.tsx
17
14
  const MIN_WIDTH = 280;
18
15
  const MAX_WIDTH = 560;
19
16
  const SCALE_FROM = .9;
20
17
  const RISE_FROM = .03;
21
- const SCRIM_OPACITY = .32;
22
- const NO_INSETS = {
23
- bottom: 0,
24
- left: 0,
25
- right: 0,
26
- top: 0
27
- };
28
- const ORIENTATIONS = [
29
- "portrait",
30
- "portrait-upside-down",
31
- "landscape",
32
- "landscape-left",
33
- "landscape-right"
34
- ];
35
18
  const NO_PARTS = {
36
19
  footer: 0,
37
20
  header: 0,
@@ -99,14 +82,6 @@ const stylesOf = themedStyles(({ colors, radii, shadows, sizing, spacing }) => S
99
82
  alignItems: "stretch",
100
83
  padding: 0
101
84
  },
102
- scrim: {
103
- backgroundColor: withOpacity(colors.scrim, SCRIM_OPACITY),
104
- bottom: 0,
105
- left: 0,
106
- position: "absolute",
107
- right: 0,
108
- top: 0
109
- },
110
85
  title: {
111
86
  color: colors.onSurface,
112
87
  flexShrink: 1
@@ -152,7 +127,7 @@ function bodyPaddingOf({ basic, parts }, spacing) {
152
127
  * `onOpenChange` to `Dialog.Content` instead.
153
128
  */
154
129
  function Dialog(t0) {
155
- const $ = c(15);
130
+ const $ = c(10);
156
131
  const { children, defaultOpen, isOpen, onOpenChange } = t0;
157
132
  let t1;
158
133
  if ($[0] !== defaultOpen || $[1] !== isOpen || $[2] !== onOpenChange) {
@@ -166,51 +141,28 @@ function Dialog(t0) {
166
141
  $[2] = onOpenChange;
167
142
  $[3] = t1;
168
143
  } else t1 = $[3];
169
- const state = useOverlayTriggerState(t1);
170
- const [trigger, setTrigger] = useState(null);
144
+ const { context, slots } = useModalTrigger(t1);
171
145
  let t2;
172
- if ($[4] !== state || $[5] !== trigger) {
173
- t2 = {
174
- state,
175
- trigger
176
- };
177
- $[4] = state;
178
- $[5] = trigger;
179
- $[6] = t2;
180
- } else t2 = $[6];
181
- const context = t2;
182
- let t3;
183
- if ($[7] !== state) {
184
- t3 = { default: (event) => {
185
- const target = event.currentTarget;
186
- setTrigger(typeof target === "number" ? null : target);
187
- state.open();
188
- } };
189
- $[7] = state;
190
- $[8] = t3;
191
- } else t3 = $[8];
192
- const slots = t3;
193
- let t4;
194
- if ($[9] !== children || $[10] !== slots) {
195
- t4 = /* @__PURE__ */ jsx(ButtonSlotContext, {
146
+ if ($[4] !== children || $[5] !== slots) {
147
+ t2 = /* @__PURE__ */ jsx(ButtonSlotContext, {
196
148
  value: slots,
197
149
  children
198
150
  });
199
- $[9] = children;
200
- $[10] = slots;
201
- $[11] = t4;
202
- } else t4 = $[11];
203
- let t5;
204
- if ($[12] !== context || $[13] !== t4) {
205
- t5 = /* @__PURE__ */ jsx(DialogTriggerContext, {
151
+ $[4] = children;
152
+ $[5] = slots;
153
+ $[6] = t2;
154
+ } else t2 = $[6];
155
+ let t3;
156
+ if ($[7] !== context || $[8] !== t2) {
157
+ t3 = /* @__PURE__ */ jsx(DialogTriggerContext, {
206
158
  value: context,
207
- children: t4
159
+ children: t2
208
160
  });
209
- $[12] = context;
210
- $[13] = t4;
211
- $[14] = t5;
212
- } else t5 = $[14];
213
- return t5;
161
+ $[7] = context;
162
+ $[8] = t2;
163
+ $[9] = t3;
164
+ } else t3 = $[9];
165
+ return t3;
214
166
  }
215
167
  /**
216
168
  * What the dialog shows, as a body that scrolls when its content runs past
@@ -316,7 +268,7 @@ function DialogBody(t0) {
316
268
  * `style`, `ref` and `testID` land on the container.
317
269
  */
318
270
  function DialogContent(t0) {
319
- const $ = c(46);
271
+ const $ = c(49);
320
272
  let children;
321
273
  let defaultOpen;
322
274
  let isOpen;
@@ -365,8 +317,7 @@ function DialogContent(t0) {
365
317
  $[12] = onOpenChange;
366
318
  $[13] = t4;
367
319
  } else t4 = $[13];
368
- const own = useOverlayTriggerState(t4);
369
- const state = outer?.state ?? own;
320
+ const { close, present, setPresent, slots, state } = useModalState(outer, t4);
370
321
  const theme = useTheme();
371
322
  const styles = stylesOf(theme);
372
323
  const insets = use(SafeAreaInsetsContext) ?? NO_INSETS;
@@ -381,133 +332,110 @@ function DialogContent(t0) {
381
332
  } else t5 = $[14];
382
333
  const [register] = useState(t5);
383
334
  const [title, setTitle] = useState(null);
384
- const [present, setPresent] = useState(state.isOpen);
385
335
  const motion = useDialogMotion(state.isOpen, present, setPresent, basic);
386
336
  let t6;
387
- if ($[15] !== state) {
388
- t6 = () => {
389
- state.close();
390
- };
391
- $[15] = state;
392
- $[16] = t6;
393
- } else t6 = $[16];
394
- const close = t6;
395
- let t7;
396
- if ($[17] !== close) {
397
- t7 = { close };
398
- $[17] = close;
399
- $[18] = t7;
400
- } else t7 = $[18];
401
- const slots = t7;
402
- let t8;
403
- if ($[19] !== basic || $[20] !== parts || $[21] !== register || $[22] !== titleId) {
404
- t8 = {
337
+ if ($[15] !== basic || $[16] !== parts || $[17] !== register || $[18] !== titleId) {
338
+ t6 = {
405
339
  basic,
406
340
  parts,
407
341
  register,
408
342
  setTitle,
409
343
  titleId
410
344
  };
411
- $[19] = basic;
412
- $[20] = parts;
413
- $[21] = register;
414
- $[22] = titleId;
415
- $[23] = t8;
416
- } else t8 = $[23];
417
- const layout = t8;
418
- if (state.isOpen && !present) setPresent(true);
419
- useReturnFocus(present, outer);
345
+ $[15] = basic;
346
+ $[16] = parts;
347
+ $[17] = register;
348
+ $[18] = titleId;
349
+ $[19] = t6;
350
+ } else t6 = $[19];
351
+ const layout = t6;
420
352
  if (!present) return null;
421
353
  const labelledBy = parts.title > 0 ? titleId : void 0;
422
- const web = Platform.OS === "web";
423
- let t9;
424
- if ($[24] !== title) {
425
- t9 = focusOf(title);
426
- $[24] = title;
427
- $[25] = t9;
428
- } else t9 = $[25];
429
- const T0 = View;
430
- const t10 = composeStyles(styles.layout, basic ? void 0 : styles.layoutFull);
431
- const t11 = Animated;
432
- let t12;
433
- if ($[26] !== labelledBy || $[27] !== role) {
434
- t12 = web ? void 0 : panelRoleOf(role, labelledBy);
435
- $[26] = labelledBy;
436
- $[27] = role;
437
- $[28] = t12;
438
- } else t12 = $[28];
439
- const t13 = isKeyboardDismissDisabled ? void 0 : close;
440
- const t14 = composeStyles(styles.container, basic ? styles.containerBasic : styles.containerFull, basic ? void 0 : insetsOf(insets), motion.panel, style);
441
- let t15;
442
- if ($[29] !== children || $[30] !== slots) {
443
- t15 = /* @__PURE__ */ jsx(ButtonSlotContext, {
354
+ const T0 = ModalWindow;
355
+ const t7 = isDismissable && state.isOpen ? close : void 0;
356
+ const t8 = motion.scrim;
357
+ const T1 = View;
358
+ const t9 = composeStyles(styles.layout, basic ? void 0 : styles.layoutFull);
359
+ const t10 = Animated;
360
+ let t11;
361
+ if ($[20] !== labelledBy || $[21] !== role) {
362
+ t11 = panelRoleOf(role, labelledBy);
363
+ $[20] = labelledBy;
364
+ $[21] = role;
365
+ $[22] = t11;
366
+ } else t11 = $[22];
367
+ const t12 = isKeyboardDismissDisabled ? void 0 : close;
368
+ const t13 = composeStyles(styles.container, basic ? styles.containerBasic : styles.containerFull, basic ? void 0 : insetsOf(insets), motion.panel, style);
369
+ let t14;
370
+ if ($[23] !== children || $[24] !== slots) {
371
+ t14 = /* @__PURE__ */ jsx(ButtonSlotContext, {
444
372
  value: slots,
445
373
  children
446
374
  });
447
- $[29] = children;
448
- $[30] = slots;
449
- $[31] = t15;
450
- } else t15 = $[31];
451
- let t16;
452
- if ($[32] !== layout || $[33] !== t15) {
453
- t16 = /* @__PURE__ */ jsx(DialogLayoutContext, {
375
+ $[23] = children;
376
+ $[24] = slots;
377
+ $[25] = t14;
378
+ } else t14 = $[25];
379
+ let t15;
380
+ if ($[26] !== layout || $[27] !== t14) {
381
+ t15 = /* @__PURE__ */ jsx(DialogLayoutContext, {
454
382
  value: layout,
383
+ children: t14
384
+ });
385
+ $[26] = layout;
386
+ $[27] = t14;
387
+ $[28] = t15;
388
+ } else t15 = $[28];
389
+ let t16;
390
+ if ($[29] !== props || $[30] !== t10.View || $[31] !== t11 || $[32] !== t12 || $[33] !== t13 || $[34] !== t15) {
391
+ t16 = /* @__PURE__ */ jsx(t10.View, {
392
+ ...t11,
393
+ onAccessibilityEscape: t12,
394
+ ...props,
395
+ style: t13,
455
396
  children: t15
456
397
  });
457
- $[32] = layout;
458
- $[33] = t15;
459
- $[34] = t16;
460
- } else t16 = $[34];
398
+ $[29] = props;
399
+ $[30] = t10.View;
400
+ $[31] = t11;
401
+ $[32] = t12;
402
+ $[33] = t13;
403
+ $[34] = t15;
404
+ $[35] = t16;
405
+ } else t16 = $[35];
461
406
  let t17;
462
- if ($[35] !== props || $[36] !== t11.View || $[37] !== t12 || $[38] !== t13 || $[39] !== t14 || $[40] !== t16) {
463
- t17 = /* @__PURE__ */ jsx(t11.View, {
464
- ...t12,
465
- onAccessibilityEscape: t13,
466
- ...props,
467
- style: t14,
407
+ if ($[36] !== T1 || $[37] !== t16 || $[38] !== t9) {
408
+ t17 = /* @__PURE__ */ jsx(T1, {
409
+ style: t9,
468
410
  children: t16
469
411
  });
470
- $[35] = props;
471
- $[36] = t11.View;
472
- $[37] = t12;
473
- $[38] = t13;
474
- $[39] = t14;
475
- $[40] = t16;
476
- $[41] = t17;
477
- } else t17 = $[41];
412
+ $[36] = T1;
413
+ $[37] = t16;
414
+ $[38] = t9;
415
+ $[39] = t17;
416
+ } else t17 = $[39];
478
417
  let t18;
479
- if ($[42] !== T0 || $[43] !== t10 || $[44] !== t17) {
418
+ if ($[40] !== T0 || $[41] !== close || $[42] !== isKeyboardDismissDisabled || $[43] !== labelledBy || $[44] !== motion.scrim || $[45] !== t17 || $[46] !== t7 || $[47] !== title) {
480
419
  t18 = /* @__PURE__ */ jsx(T0, {
481
- style: t10,
420
+ isKeyboardDismissDisabled,
421
+ labelledBy,
422
+ onClose: close,
423
+ onScrimPress: t7,
424
+ scrim: t8,
425
+ title,
482
426
  children: t17
483
427
  });
484
- $[42] = T0;
485
- $[43] = t10;
486
- $[44] = t17;
487
- $[45] = t18;
488
- } else t18 = $[45];
489
- return /* @__PURE__ */ jsx(Modal, {
490
- animationType: "none",
491
- "aria-labelledby": web ? labelledBy : void 0,
492
- navigationBarTranslucent: true,
493
- onRequestClose: isKeyboardDismissDisabled ? ignore : close,
494
- onShow: t9,
495
- statusBarTranslucent: true,
496
- supportedOrientations: ORIENTATIONS,
497
- transparent: true,
498
- visible: true,
499
- children: /* @__PURE__ */ jsx(ButtonSlotContext, {
500
- value: null,
501
- children: /* @__PURE__ */ jsxs(OverlayHost, { children: [/* @__PURE__ */ jsx(AnimatedPressable, {
502
- accessible: false,
503
- "aria-hidden": true,
504
- focusable: false,
505
- onPress: isDismissable && state.isOpen ? close : void 0,
506
- style: composeStyles(styles.scrim, motion.scrim),
507
- tabIndex: -1
508
- }), t18] })
509
- })
510
- });
428
+ $[40] = T0;
429
+ $[41] = close;
430
+ $[42] = isKeyboardDismissDisabled;
431
+ $[43] = labelledBy;
432
+ $[44] = motion.scrim;
433
+ $[45] = t17;
434
+ $[46] = t7;
435
+ $[47] = title;
436
+ $[48] = t18;
437
+ } else t18 = $[48];
438
+ return t18;
511
439
  }
512
440
  /**
513
441
  * The dialog's actions, at the trailing edge and wrapping onto another row
@@ -675,48 +603,6 @@ function DialogTitle(t0) {
675
603
  } else t7 = $[15];
676
604
  return t7;
677
605
  }
678
- function focusOf(title) {
679
- return () => {
680
- if (title !== null && Platform.OS !== "web") AccessibilityInfo.sendAccessibilityEvent(title, "focus");
681
- };
682
- }
683
- function ignore() {}
684
- function insetsOf(insets) {
685
- return {
686
- paddingBottom: insets.bottom,
687
- paddingLeft: insets.left,
688
- paddingRight: insets.right,
689
- paddingTop: insets.top
690
- };
691
- }
692
- function panelRoleOf(role, labelledBy) {
693
- return {
694
- "aria-labelledby": labelledBy,
695
- "aria-modal": true,
696
- role
697
- };
698
- }
699
- function refsOf(own, other) {
700
- return (node) => {
701
- own(node);
702
- if (typeof other === "function") other(node);
703
- else if (other !== null && other !== void 0) other.current = node;
704
- };
705
- }
706
- function registerOf(setParts) {
707
- return (part) => {
708
- setParts((parts) => ({
709
- ...parts,
710
- [part]: parts[part] + 1
711
- }));
712
- return () => {
713
- setParts((parts) => ({
714
- ...parts,
715
- [part]: parts[part] - 1
716
- }));
717
- };
718
- };
719
- }
720
606
  /**
721
607
  * The scrim's and the panel's motion, and the timer that unmounts the dialog
722
608
  * once its exit has run. The panel arrives over the medium duration on the
@@ -826,30 +712,6 @@ function useLayout(part) {
826
712
  if (layout === null) throw new Error(`${part} is drawn inside Dialog.Content.`);
827
713
  return layout;
828
714
  }
829
- function useReturnFocus(present, outer) {
830
- const $ = c(6);
831
- const shown = useRef(present);
832
- let t0;
833
- if ($[0] !== outer?.trigger || $[1] !== present) {
834
- t0 = () => {
835
- const trigger = outer?.trigger ?? null;
836
- const gone = shown.current && !present;
837
- shown.current = present;
838
- if (gone && trigger !== null && Platform.OS !== "web") AccessibilityInfo.sendAccessibilityEvent(trigger, "focus");
839
- };
840
- $[0] = outer?.trigger;
841
- $[1] = present;
842
- $[2] = t0;
843
- } else t0 = $[2];
844
- let t1;
845
- if ($[3] !== outer || $[4] !== present) {
846
- t1 = [outer, present];
847
- $[3] = outer;
848
- $[4] = present;
849
- $[5] = t1;
850
- } else t1 = $[5];
851
- useEffect(t0, t1);
852
- }
853
715
  Dialog.Body = DialogBody;
854
716
  Dialog.Content = DialogContent;
855
717
  Dialog.Footer = DialogFooter;