@kwiz/fluentui 1.0.57 → 1.0.60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. package/.dependency-cruiser.js +399 -0
  2. package/dist/controls/ColorPickerDialog.js +1 -1
  3. package/dist/controls/ColorPickerDialog.js.map +1 -1
  4. package/dist/controls/button.js +1 -1
  5. package/dist/controls/button.js.map +1 -1
  6. package/dist/controls/canvas/DrawPad.js +1 -1
  7. package/dist/controls/canvas/DrawPad.js.map +1 -1
  8. package/dist/controls/date.js +2 -2
  9. package/dist/controls/date.js.map +1 -1
  10. package/dist/controls/diagram-picker.js +2 -2
  11. package/dist/controls/diagram-picker.js.map +1 -1
  12. package/dist/controls/dropdown.js +1 -1
  13. package/dist/controls/dropdown.js.map +1 -1
  14. package/dist/controls/file-upload.js +1 -2
  15. package/dist/controls/file-upload.js.map +1 -1
  16. package/dist/controls/index.d.ts +31 -0
  17. package/dist/controls/index.js +32 -0
  18. package/dist/controls/index.js.map +1 -0
  19. package/dist/controls/input.js +1 -1
  20. package/dist/controls/input.js.map +1 -1
  21. package/dist/controls/kwizoverflow.js +1 -1
  22. package/dist/controls/kwizoverflow.js.map +1 -1
  23. package/dist/controls/menu.js +2 -2
  24. package/dist/controls/menu.js.map +1 -1
  25. package/dist/controls/prompt.js +2 -2
  26. package/dist/controls/prompt.js.map +1 -1
  27. package/dist/controls/search.js +1 -1
  28. package/dist/controls/search.js.map +1 -1
  29. package/dist/controls/section.js +1 -1
  30. package/dist/controls/section.js.map +1 -1
  31. package/dist/controls/vertical-content.js +1 -1
  32. package/dist/controls/vertical-content.js.map +1 -1
  33. package/dist/helpers/block-nav.d.ts +11 -0
  34. package/dist/helpers/block-nav.js +79 -0
  35. package/dist/helpers/block-nav.js.map +1 -0
  36. package/dist/helpers/{context.d.ts → context-const.d.ts} +0 -1
  37. package/dist/helpers/context-const.js +4 -0
  38. package/dist/helpers/context-const.js.map +1 -0
  39. package/dist/helpers/context-export.d.ts +7 -0
  40. package/dist/helpers/context-export.js +25 -0
  41. package/dist/helpers/context-export.js.map +1 -0
  42. package/dist/helpers/context-internal.d.ts +1 -0
  43. package/dist/helpers/{context.js → context-internal.js} +2 -3
  44. package/dist/helpers/context-internal.js.map +1 -0
  45. package/dist/helpers/drag-drop/drag-drop-container.d.ts +1 -2
  46. package/dist/helpers/drag-drop/drag-drop-container.js.map +1 -1
  47. package/dist/helpers/drag-drop/drag-drop-context-internal.d.ts +4 -0
  48. package/dist/helpers/drag-drop/drag-drop-context-internal.js +9 -0
  49. package/dist/helpers/drag-drop/drag-drop-context-internal.js.map +1 -0
  50. package/dist/helpers/drag-drop/drag-drop-context.d.ts +1 -9
  51. package/dist/helpers/drag-drop/drag-drop-context.js +2 -9
  52. package/dist/helpers/drag-drop/drag-drop-context.js.map +1 -1
  53. package/dist/helpers/drag-drop/drag-drop.types.d.ts +19 -0
  54. package/dist/helpers/drag-drop/drag-drop.types.js +2 -0
  55. package/dist/helpers/drag-drop/drag-drop.types.js.map +1 -0
  56. package/dist/helpers/drag-drop/{exports.d.ts → index.d.ts} +2 -4
  57. package/dist/helpers/drag-drop/{exports.js → index.js} +1 -1
  58. package/dist/helpers/drag-drop/index.js.map +1 -0
  59. package/dist/helpers/drag-drop/use-draggable.d.ts +1 -8
  60. package/dist/helpers/drag-drop/use-draggable.js +1 -1
  61. package/dist/helpers/drag-drop/use-draggable.js.map +1 -1
  62. package/dist/helpers/drag-drop/use-droppable.d.ts +2 -9
  63. package/dist/helpers/drag-drop/use-droppable.js +1 -2
  64. package/dist/helpers/drag-drop/use-droppable.js.map +1 -1
  65. package/dist/helpers/hooks-events.d.ts +21 -0
  66. package/dist/helpers/hooks-events.js +146 -0
  67. package/dist/helpers/hooks-events.js.map +1 -0
  68. package/dist/helpers/hooks.d.ts +0 -69
  69. package/dist/helpers/hooks.js +1 -310
  70. package/dist/helpers/hooks.js.map +1 -1
  71. package/dist/helpers/index.d.ts +7 -0
  72. package/dist/helpers/index.js +8 -0
  73. package/dist/helpers/index.js.map +1 -0
  74. package/dist/helpers/use-alerts.d.ts +14 -0
  75. package/dist/helpers/use-alerts.js +65 -0
  76. package/dist/helpers/use-alerts.js.map +1 -0
  77. package/dist/helpers/use-toast.d.ts +18 -0
  78. package/dist/helpers/use-toast.js +17 -0
  79. package/dist/helpers/use-toast.js.map +1 -0
  80. package/dist/index.d.ts +3 -36
  81. package/dist/index.js +3 -35
  82. package/dist/index.js.map +1 -1
  83. package/dist/styles/index.d.ts +1 -0
  84. package/dist/styles/index.js +2 -0
  85. package/dist/styles/index.js.map +1 -0
  86. package/package.json +5 -3
  87. package/src/controls/ColorPickerDialog.tsx +1 -1
  88. package/src/controls/button.tsx +1 -1
  89. package/src/controls/canvas/DrawPad.tsx +1 -1
  90. package/src/controls/date.tsx +2 -2
  91. package/src/controls/diagram-picker.tsx +2 -2
  92. package/src/controls/dropdown.tsx +1 -1
  93. package/src/controls/file-upload.tsx +1 -3
  94. package/src/controls/index.ts +31 -0
  95. package/src/controls/input.tsx +1 -1
  96. package/src/controls/kwizoverflow.tsx +1 -1
  97. package/src/controls/menu.tsx +2 -2
  98. package/src/controls/prompt.tsx +2 -2
  99. package/src/controls/search.tsx +1 -1
  100. package/src/controls/section.tsx +1 -1
  101. package/src/controls/vertical-content.tsx +1 -1
  102. package/src/helpers/block-nav.tsx +89 -0
  103. package/src/helpers/{context.ts → context-const.ts} +1 -13
  104. package/src/helpers/context-export.tsx +31 -0
  105. package/src/helpers/context-internal.ts +14 -0
  106. package/src/helpers/drag-drop/drag-drop-container.tsx +1 -2
  107. package/src/helpers/drag-drop/drag-drop-context-internal.tsx +10 -0
  108. package/src/helpers/drag-drop/drag-drop-context.tsx +5 -15
  109. package/src/helpers/drag-drop/drag-drop.types.ts +21 -0
  110. package/src/helpers/drag-drop/{exports.ts → index.ts} +2 -4
  111. package/src/helpers/drag-drop/use-draggable.ts +2 -10
  112. package/src/helpers/drag-drop/use-droppable.ts +3 -12
  113. package/src/helpers/hooks-events.ts +153 -0
  114. package/src/helpers/hooks.tsx +1 -360
  115. package/src/helpers/index.ts +8 -0
  116. package/src/helpers/use-alerts.tsx +75 -0
  117. package/src/helpers/use-toast.tsx +30 -0
  118. package/src/index.ts +3 -37
  119. package/src/styles/index.ts +1 -0
  120. package/dist/helpers/context.js.map +0 -1
  121. package/dist/helpers/drag-drop/exports.js.map +0 -1
@@ -3,7 +3,7 @@ import { ColorRegular } from "@fluentui/react-icons";
3
3
  import { isFunction, isNullOrEmptyString, isNumber } from "@kwiz/common";
4
4
  import * as React from "react";
5
5
  import ColorPicker, { Color } from 'react-pick-color';
6
- import { useEffectOnlyOnMount, useStateEX } from "../helpers/hooks";
6
+ import { useEffectOnlyOnMount, useStateEX } from "../helpers";
7
7
  import { ButtonEX } from "./button";
8
8
  import { InputEx } from "./input";
9
9
  import { Prompter } from "./prompt";
@@ -1,7 +1,7 @@
1
1
  import { Button, ButtonProps, CompoundButton, compoundButtonClassNames, CompoundButtonProps, makeStyles, mergeClasses, tokens, Tooltip } from '@fluentui/react-components';
2
2
  import { capitalizeFirstLetter, isFunction, isNullOrEmptyString, isNullOrUndefined, isString, PushNoDuplicate } from '@kwiz/common';
3
3
  import React from 'react';
4
- import { useKWIZFluentContext } from '../helpers/context';
4
+ import { useKWIZFluentContext } from '../helpers/context-internal';
5
5
  import { commonSizes, useCommonStyles } from '../styles/styles';
6
6
 
7
7
  interface IProps {
@@ -2,7 +2,7 @@ import { Field, tokens } from "@fluentui/react-components";
2
2
  import { ArrowMaximizeRegular, ArrowMinimizeRegular, ArrowUploadRegular, CalligraphyPenRegular, DismissRegular } from "@fluentui/react-icons";
3
3
  import { debounce, getCSSVariableValue, ImageFileTypes, isElement, isNotEmptyString, isNullOrEmptyArray, isNullOrEmptyString, isNullOrUndefined } from "@kwiz/common";
4
4
  import * as React from "react";
5
- import { useAlerts, useElementSize, useStateEX } from "../../helpers/hooks";
5
+ import { useAlerts, useElementSize, useStateEX } from "../../helpers";
6
6
  import { ButtonEX } from "../button";
7
7
  import { ColorPickerEx } from "../ColorPickerDialog";
8
8
  import { FileUpload } from "../file-upload";
@@ -4,8 +4,8 @@ import { TimePicker, TimePickerProps } from '@fluentui/react-timepicker-compat';
4
4
  import { CalendarCancelRegular } from '@fluentui/react-icons';
5
5
  import { isDate } from '@kwiz/common';
6
6
  import * as React from 'react';
7
- import { useKWIZFluentContext } from '../helpers/context';
8
- import { useStateEX } from '../helpers/hooks';
7
+ import { useKWIZFluentContext } from '../helpers/context-internal';
8
+ import { useStateEX } from '../helpers';
9
9
  import { Horizontal } from './horizontal';
10
10
 
11
11
  interface IProps {
@@ -2,8 +2,8 @@ import { Dialog, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTr
2
2
  import { ImageSparkleRegular } from '@fluentui/react-icons';
3
3
  import { DiagramOptions, stockUrl } from '@kwiz/common';
4
4
  import React from 'react';
5
- import { useKWIZFluentContext } from '../helpers/context';
6
- import { useStateEX } from '../helpers/hooks';
5
+ import { useKWIZFluentContext } from '../helpers/context-internal';
6
+ import { useStateEX } from '../helpers';
7
7
  import { ButtonEXPrimarySubtle } from './button';
8
8
  import { Horizontal } from './horizontal';
9
9
  import { Section } from './section';
@@ -1,7 +1,7 @@
1
1
  import { Dropdown, DropdownProps, makeStyles, mergeClasses, Option } from '@fluentui/react-components';
2
2
  import { filterEmptyEntries, firstOrNull, isNullOrUndefined } from '@kwiz/common';
3
3
  import React from 'react';
4
- import { useKWIZFluentContext } from '../helpers/context';
4
+ import { useKWIZFluentContext } from '../helpers/context-internal';
5
5
 
6
6
  const useStyles = makeStyles({
7
7
  root: {
@@ -2,9 +2,7 @@ import { makeStyles, shorthands, tokens } from "@fluentui/react-components";
2
2
  import { ArrowUploadRegular } from "@fluentui/react-icons";
3
3
  import { isFunction, isNotEmptyArray, isNotEmptyString, isNullOrEmptyString, lastOrNull } from '@kwiz/common';
4
4
  import * as React from "react";
5
- import { useDragDropContext } from "../helpers/drag-drop/drag-drop-context";
6
- import { dropFiles } from "../helpers/drag-drop/exports";
7
- import { useEffectOnlyOnMount } from "../helpers/hooks";
5
+ import { dropFiles, useDragDropContext, useEffectOnlyOnMount } from "../helpers";
8
6
  import { ButtonEX, ButtonEXProps, CompoundButtonEXSecondary } from "./button";
9
7
 
10
8
  const useStyles = makeStyles({
@@ -0,0 +1,31 @@
1
+ export * from './accordion';
2
+ export * from './button';
3
+ export * from './canvas/DrawPad';
4
+ export * from './card';
5
+ export * from './card-list';
6
+ export * from './centered';
7
+ export * from './ColorPickerDialog';
8
+ export * from './date';
9
+ export * from './diagram-picker';
10
+ export * from './divider';
11
+ export * from './dropdown';
12
+ export * from './error-boundary';
13
+ export * from './field-editor';
14
+ export * from './file-upload';
15
+ export * from './horizontal';
16
+ export * from './html-editor/editor';
17
+ export * from './input';
18
+ export * from './kwizoverflow';
19
+ export * from './list';
20
+ export * from './loading';
21
+ export * from './menu';
22
+ export * from './please-wait';
23
+ export * from './progress-bar';
24
+ export * from './prompt';
25
+ export * from './qrcode';
26
+ export * from './search';
27
+ export * from './section';
28
+ export * from './svg';
29
+ export * from './toolbar';
30
+ export * from './vertical';
31
+ export * from './vertical-content';
@@ -1,7 +1,7 @@
1
1
  import { GriffelStyle, Input, InputOnChangeData, InputProps, Label, Link, makeStyles, mergeClasses, Textarea, TextareaProps } from '@fluentui/react-components';
2
2
  import { isFunction, isNotEmptyArray, isNullOrEmptyString, isNullOrNaN, isNullOrUndefined, isNumber } from '@kwiz/common';
3
3
  import React from 'react';
4
- import { useKWIZFluentContext } from '../helpers/context';
4
+ import { useKWIZFluentContext } from '../helpers/context-internal';
5
5
  import { useCommonStyles } from '../styles/styles';
6
6
  import { Horizontal } from './horizontal';
7
7
  import { MenuEx } from './menu';
@@ -4,7 +4,7 @@ import {
4
4
  } from "@fluentui/react-components";
5
5
  import { MoreHorizontalFilled } from "@fluentui/react-icons";
6
6
  import { isNumber } from '@kwiz/common';
7
- import { useKWIZFluentContext } from "../helpers/context";
7
+ import { useKWIZFluentContext } from "../helpers/context-internal";
8
8
 
9
9
  interface IProps<ItemType> {
10
10
  /** you cannot have a menu with trigger in overflow items. put those in groupWrapper controls before/after rendering children. */
@@ -2,8 +2,8 @@ import { Menu, MenuDivider, MenuGroup, MenuGroupHeader, MenuItem, MenuList, Menu
2
2
  import { ChevronLeftRegular, ChevronRightRegular } from '@fluentui/react-icons';
3
3
  import { IDictionary, isNotEmptyArray, isNotEmptyString, isNullOrEmptyString, isNullOrUndefined, isNumber, isString, isUndefined, jsonClone, stopEvent } from '@kwiz/common';
4
4
  import React from 'react';
5
- import { useKWIZFluentContext } from '../helpers/context';
6
- import { useStateEX } from '../helpers/hooks';
5
+ import { useKWIZFluentContext } from '../helpers/context-internal';
6
+ import { useStateEX } from '../helpers';
7
7
  import { ButtonEX, ButtonEXProps } from './button';
8
8
  import { Horizontal } from './horizontal';
9
9
  import { Search } from './search';
@@ -2,8 +2,8 @@ import { Dialog, DialogActions, DialogBody, DialogContent, DialogModalType, Dial
2
2
  import { DismissRegular } from '@fluentui/react-icons';
3
3
  import { isNotEmptyArray, isNullOrEmptyString, noops, PushNoDuplicate, RemoveItemFromArr, stopEvent } from '@kwiz/common';
4
4
  import React from 'react';
5
- import { useKWIZFluentContext } from '../helpers/context';
6
- import { useKeyDown } from '../helpers/hooks';
5
+ import { useKWIZFluentContext } from '../helpers/context-internal';
6
+ import { useKeyDown } from '../helpers/hooks-events';
7
7
  import { ButtonEX, ButtonEXProps, ButtonEXSecondary } from './button';
8
8
 
9
9
  export interface IPrompterProps {
@@ -3,7 +3,7 @@ import { DismissRegular, SearchRegular } from "@fluentui/react-icons";
3
3
  import { debounce, isFunction, isNullOrEmptyString, isUndefined } from '@kwiz/common';
4
4
  import React, { useState } from 'react';
5
5
  import { GetLogger } from '../_modules/config';
6
- import { useStateEX } from '../helpers/hooks';
6
+ import { useStateEX } from '../helpers';
7
7
  import { mixins } from '../styles/styles';
8
8
  const logger = GetLogger("Search");
9
9
 
@@ -1,7 +1,7 @@
1
1
  import { makeStyles, mergeClasses, Portal, tokens } from '@fluentui/react-components';
2
2
  import { isFunction, isNotEmptyArray } from '@kwiz/common';
3
3
  import React from 'react';
4
- import { useKWIZFluentContext } from '../helpers/context';
4
+ import { useKWIZFluentContext } from '../helpers/context-internal';
5
5
  import { KnownClassNames, mixins, useCommonStyles } from '../styles/styles';
6
6
 
7
7
  const useStyles = makeStyles({
@@ -1,7 +1,7 @@
1
1
  import { makeStyles, mergeClasses } from '@fluentui/react-components';
2
2
  import { isNotEmptyArray } from '@kwiz/common';
3
3
  import React from 'react';
4
- import { useWindowSize } from '../helpers/hooks';
4
+ import { useWindowSize } from '../helpers';
5
5
 
6
6
  const useStyles = makeStyles({
7
7
  verticalContainer: {
@@ -0,0 +1,89 @@
1
+ import { IDictionary, isNotEmptyArray, isNullOrEmptyString, jsonClone, objectsEqual } from "@kwiz/common";
2
+ import { useCallback, useEffect } from "react";
3
+ import { IPrompterProps, Prompter } from "../controls/prompt";
4
+ import { useEffectOnlyOnMount, useStateEX } from "./hooks";
5
+
6
+ export interface iBlockNav {
7
+ setMessage: (id: string, message?: string) => void;
8
+ onNav: (nav: () => void) => void;
9
+ navPrompt?: JSX.Element;
10
+
11
+ }
12
+ /** set block message if you want to block nav.
13
+ * - call setMessage to add a blocker message
14
+ * - call onNav when you have internal navigation (open / close popups)
15
+ * - render the navPrompt control to your page
16
+ * FYI for page unload, most modern browsers won't show your message but a generic one instead. */
17
+ export function useBlockNav(): iBlockNav {
18
+ const [, setBlockNavMessages, blockNavMessagesRef] = useStateEX<IDictionary<string>>({});
19
+ const [_prompt, setPrompt] = useStateEX<IPrompterProps>(null);
20
+
21
+ const getMessagesArr = useCallback(() => {
22
+ return Object.keys(blockNavMessagesRef.current).map(id => blockNavMessagesRef.current[id]);
23
+ }, useEffectOnlyOnMount);
24
+
25
+ const getMessages = useCallback(() => {
26
+ return getMessagesArr().join();
27
+ }, useEffectOnlyOnMount);
28
+
29
+ const onNav = useCallback((nav: () => void) => {
30
+ let messages = getMessagesArr();
31
+ if (isNotEmptyArray(messages)) {
32
+ //need to release react to re-render the prompt
33
+ window.setTimeout(() => {
34
+ //prompt, if ok - clear messages and nav.
35
+ setPrompt({
36
+ okButtonText: "Leave",
37
+ cancelButtonText: "Cancel",
38
+ title: "Leave page?",
39
+ children: messages.length > 1
40
+ ? <ul>
41
+ {messages.map((m, i) => <li key={`m${i}`}>{m}</li>)}
42
+ </ul>
43
+ : <p>{messages[0]}</p>,
44
+ onCancel: () => setPrompt(null),
45
+ onOK: () => {
46
+ setPrompt(null);
47
+ setBlockNavMessages({});//clear messages
48
+ nav();
49
+ }
50
+ });
51
+ }, 1);
52
+ }
53
+ else nav();
54
+ }, useEffectOnlyOnMount);
55
+
56
+
57
+ useEffect(() => {
58
+ function handleBeforeUnload(e: BeforeUnloadEvent) {
59
+ //todo: use blockMessageRef.current so that we don't have to re-register every time message changes.
60
+ //otherwise we would have to add blockMessage as a dependency for this useEffect
61
+ const message = getMessages();
62
+ if (!isNullOrEmptyString(message)) {
63
+ e.preventDefault();
64
+ e.returnValue = message;
65
+ }
66
+ }
67
+ // Add event listener
68
+ window.addEventListener("beforeunload", handleBeforeUnload);
69
+ // Remove event listener on cleanup
70
+ return () => window.removeEventListener("beforeunload", handleBeforeUnload);
71
+ }, useEffectOnlyOnMount);
72
+ return {
73
+ setMessage: (id: string, message?: string) => {
74
+ let current = jsonClone(blockNavMessagesRef.current);
75
+ if (isNullOrEmptyString(message))
76
+ delete current[id];
77
+ else current[id] = message;
78
+ if (!objectsEqual(current, blockNavMessagesRef.current))
79
+ setBlockNavMessages(current);
80
+ },
81
+ // clearMessages: () => {
82
+ // setBlockNavMessages({});
83
+ // },
84
+ // getMessages,
85
+ // getMessagesArr,
86
+ onNav,
87
+ navPrompt: _prompt ? <Prompter {..._prompt} /> : undefined
88
+ };
89
+ }
@@ -1,6 +1,4 @@
1
- import { isNullOrUndefined } from "@kwiz/common";
2
1
  import React from "react";
3
-
4
2
  export interface iKWIZFluentContext {
5
3
  /**
6
4
  * Where the portal children are mounted on DOM
@@ -27,14 +25,4 @@ export interface iKWIZFluentContext {
27
25
  }
28
26
 
29
27
  //create context
30
- export const KWIZFluentContext = React.createContext<iKWIZFluentContext>(null);
31
- //use context from within controls
32
- export function useKWIZFluentContext() {
33
- let ctx = React.useContext(KWIZFluentContext) || {};
34
- //set defaults
35
- if (isNullOrUndefined(ctx.inputAppearance))
36
- ctx.inputAppearance = "underline";
37
- if (isNullOrUndefined(ctx.buttonShape))
38
- ctx.buttonShape = "circular";
39
- return ctx;
40
- }
28
+ export const KWIZFluentContext = React.createContext<iKWIZFluentContext>(null);
@@ -0,0 +1,31 @@
1
+ import { makeStyles } from "@fluentui/react-components";
2
+ import React, { PropsWithChildren, useEffect, useState } from "react";
3
+ import { iKWIZFluentContext, KWIZFluentContext } from "./context-const";
4
+ export type { iKWIZFluentContext } from "./context-const";
5
+
6
+ const useContextStyles = makeStyles({
7
+ root: {
8
+ "& *": {
9
+ scrollbarWidth: "thin"
10
+ }
11
+ },
12
+ })
13
+
14
+ export function useKWIZFluentContextProvider(options: {
15
+ root?: React.MutableRefObject<HTMLDivElement>;
16
+ ctx?: iKWIZFluentContext;
17
+ }) {
18
+ const classes = useContextStyles();
19
+ let v: iKWIZFluentContext = options && options.ctx || {};
20
+ const [kwizFluentContext, setKwizFluentContext] = useState<iKWIZFluentContext>(v);
21
+ useEffect(() => {
22
+ options.root?.current?.classList.add(...classes.root.split(' '));
23
+ // ref only updates in useEffect, not in useMemo or anything else.
24
+ // we need to set it into state so it will trigger a ui update
25
+ setKwizFluentContext({
26
+ ...v,
27
+ mountNode: options.root.current
28
+ });
29
+ }, [options.root]);
30
+ return (props: PropsWithChildren) => <KWIZFluentContext.Provider value={kwizFluentContext}>{props.children}</KWIZFluentContext.Provider>;
31
+ }
@@ -0,0 +1,14 @@
1
+ import { isNullOrUndefined } from "@kwiz/common";
2
+ import React from "react";
3
+ import { KWIZFluentContext } from "./context-const";
4
+
5
+ //use context from within controls
6
+ export function useKWIZFluentContext() {
7
+ let ctx = React.useContext(KWIZFluentContext) || {};
8
+ //set defaults
9
+ if (isNullOrUndefined(ctx.inputAppearance))
10
+ ctx.inputAppearance = "underline";
11
+ if (isNullOrUndefined(ctx.buttonShape))
12
+ ctx.buttonShape = "circular";
13
+ return ctx;
14
+ }
@@ -1,7 +1,6 @@
1
1
  import { mergeClasses } from "@fluentui/react-components";
2
2
  import { useDragDropContext } from "./drag-drop-context";
3
- import { iDraggableProps, iDraggedItemType } from "./use-draggable";
4
- import { iDroppableProps } from "./use-droppable";
3
+ import { iDraggableProps, iDraggedItemType, iDroppableProps } from "./drag-drop.types";
5
4
 
6
5
  interface one<DragItemType extends iDraggedItemType<string>> {
7
6
  dragInfo: iDraggableProps<DragItemType>;
@@ -0,0 +1,10 @@
1
+ import React, { useContext } from "react";
2
+ import { iDragDropContext } from "./drag-drop.types";
3
+
4
+ //create context
5
+ export const DragDropContext = React.createContext<iDragDropContext>(null);
6
+ //use context from within controls
7
+ export function useDragDropContextInternal() {
8
+ const dragDropContext = useContext(DragDropContext);
9
+ return dragDropContext;
10
+ }
@@ -1,23 +1,13 @@
1
1
  import { isNullOrUndefined } from "@kwiz/common";
2
- import React, { useContext } from "react";
2
+ import React from "react";
3
3
  import { DndProvider } from "react-dnd";
4
4
  import { HTML5Backend } from "react-dnd-html5-backend";
5
5
  import { useStateEX } from "../hooks";
6
- import { iDraggableProps, iDraggedItemType, useDraggable } from "./use-draggable";
7
- import useDroppable, { iDroppableProps } from "./use-droppable";
6
+ import { DragDropContext, useDragDropContextInternal } from "./drag-drop-context-internal";
7
+ import { iDragDropContext, iDraggableProps, iDraggedItemType, iDroppableProps } from "./drag-drop.types";
8
+ import { useDraggable } from "./use-draggable";
9
+ import { useDroppable } from "./use-droppable";
8
10
 
9
- export interface iDragDropContext {
10
- isDragging: boolean;
11
- dragItem: iDraggedItemType<string>;
12
- setDragItem: (value: iDraggedItemType<string>) => void;
13
- }
14
- //create context
15
- export const DragDropContext = React.createContext<iDragDropContext>(null);
16
- //use context from within controls
17
- export function useDragDropContextInternal() {
18
- const dragDropContext = useContext(DragDropContext);
19
- return dragDropContext;
20
- }
21
11
  export function useDragDropContext<
22
12
  DragItemType extends iDraggedItemType<string> = never,
23
13
  DropInfoType extends iDroppableProps<string, any> = never
@@ -0,0 +1,21 @@
1
+ export interface iDraggedItemType<DragType extends string> {
2
+ type: DragType;
3
+ }
4
+ export interface iDraggableProps<ItemType extends iDraggedItemType<string>> {
5
+ item: ItemType;
6
+ onBeginDrag?: () => void;
7
+ onEndDrag?: (dropResult: any) => void;
8
+ }
9
+
10
+ export interface iDroppableProps<DropTypes extends string, ItemTypes extends iDraggedItemType<DropTypes>> {
11
+ acceptTypes: DropTypes[];
12
+ onItemDrop: (item: ItemTypes) => void;
13
+ onHover?: (item: ItemTypes) => void;
14
+ onDrop?: () => void;
15
+ }
16
+
17
+ export interface iDragDropContext {
18
+ isDragging: boolean;
19
+ dragItem: iDraggedItemType<string>;
20
+ setDragItem: (value: iDraggedItemType<string>) => void;
21
+ }
@@ -1,11 +1,9 @@
1
1
  import { NativeTypes } from 'react-dnd-html5-backend';
2
- import { iDraggedItemType } from './use-draggable';
3
- import { iDroppableProps } from './use-droppable';
2
+ import { iDraggedItemType, iDroppableProps } from './drag-drop.types';
4
3
 
5
4
  export { DragDropContainer } from './drag-drop-container';
6
5
  export { DragDropContextProvider, useDragDropContext } from "./drag-drop-context";
7
- export type { iDraggedItemType } from "./use-draggable";
8
- export type { iDroppableProps } from "./use-droppable";
6
+ export type { iDraggedItemType, iDroppableProps } from "./drag-drop.types";
9
7
 
10
8
  type fileNativeType = typeof NativeTypes.FILE;
11
9
  interface dragFiles extends iDraggedItemType<fileNativeType> {
@@ -1,15 +1,7 @@
1
1
  import { useEffect } from 'react';
2
2
  import { ConnectDragSource, DragSourceMonitor, useDrag } from 'react-dnd';
3
- import { useDragDropContextInternal } from './drag-drop-context';
4
-
5
- export interface iDraggedItemType<DragType extends string> {
6
- type: DragType;
7
- }
8
- export interface iDraggableProps<ItemType extends iDraggedItemType<string>> {
9
- item: ItemType;
10
- onBeginDrag?: () => void;
11
- onEndDrag?: (dropResult: any) => void;
12
- }
3
+ import { useDragDropContextInternal } from './drag-drop-context-internal';
4
+ import { iDraggableProps, iDraggedItemType } from './drag-drop.types';
13
5
 
14
6
  export function useDraggable<ItemType extends iDraggedItemType<string>>(props?: iDraggableProps<ItemType>): {
15
7
  isDragging: boolean;
@@ -1,14 +1,7 @@
1
1
  import { ConnectDropTarget, DropTargetMonitor, useDrop } from 'react-dnd';
2
- import { iDraggedItemType } from './use-draggable';
2
+ import { iDraggedItemType, iDroppableProps } from './drag-drop.types';
3
3
 
4
- export interface iDroppableProps<DropTypes extends string, ItemTypes extends iDraggedItemType<DropTypes>> {
5
- acceptTypes: DropTypes[];
6
- onItemDrop: (item: ItemTypes) => void;
7
- onHover?: (item: ItemTypes) => void;
8
- onDrop?: () => void;
9
- }
10
-
11
- function useDroppable<DropType extends string, ItemType extends iDraggedItemType<DropType>>(props?: iDroppableProps<DropType, ItemType>): {
4
+ export function useDroppable<DropType extends string, ItemType extends iDraggedItemType<DropType>>(props?: iDroppableProps<DropType, ItemType>): {
12
5
  canDrop: boolean;
13
6
  isOver: boolean;
14
7
  dropRef: ConnectDropTarget;
@@ -43,6 +36,4 @@ function useDroppable<DropType extends string, ItemType extends iDraggedItemType
43
36
  isOver,
44
37
  dropRef,
45
38
  };
46
- }
47
-
48
- export default useDroppable;
39
+ }
@@ -0,0 +1,153 @@
1
+ import { isDebug, isFunction } from "@kwiz/common";
2
+ import { MutableRefObject, useEffect, useRef, useState } from "react";
3
+ import { KnownClassNames } from "../styles/styles";
4
+ import { useEffectOnlyOnMount } from "./hooks";
5
+
6
+ export function useTrackFocus(props: { onFocus: () => void, onLoseFocus: () => void, ref?: MutableRefObject<HTMLElement> }) {
7
+ const wrapperDiv = props.ref || useRef<HTMLDivElement>(null);
8
+ useEffect(() => {
9
+ function focusIn(e: FocusEvent) {
10
+ let elm = e.target as HTMLElement;//document.activeElement;
11
+ if (wrapperDiv.current) {
12
+ while (elm && elm !== wrapperDiv.current) {
13
+ elm = elm.parentElement;
14
+ }
15
+ } else elm = null;
16
+ if (wrapperDiv.current && elm === wrapperDiv.current) props.onFocus();
17
+ else props.onLoseFocus();
18
+ }
19
+
20
+ if (wrapperDiv.current) {
21
+ if (wrapperDiv.current) wrapperDiv.current.tabIndex = 1;
22
+ window.addEventListener("focusin", focusIn);
23
+ // Remove event listener on cleanup
24
+ return () => window.removeEventListener("focusin", focusIn);
25
+ }
26
+ }, [wrapperDiv.current]);
27
+ return wrapperDiv;
28
+ }
29
+ export function useWindowSize() {
30
+ // Initialize state with undefined width/height so server and client renders match
31
+ // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
32
+ const [windowSize, setWindowSize] = useState<{
33
+ width: number,
34
+ height: number
35
+ }>({
36
+ width: undefined,
37
+ height: undefined
38
+ });
39
+ useEffect(() => {
40
+ // Handler to call on window resize
41
+ function handleResize() {
42
+
43
+ // Set window width/height to state
44
+ setWindowSize({
45
+ width: window.innerWidth,
46
+ height: window.innerHeight
47
+ });
48
+ }
49
+ // Add event listener
50
+ window.addEventListener("resize", handleResize);
51
+ // Call handler right away so state gets updated with initial window size
52
+ handleResize();
53
+ // Remove event listener on cleanup
54
+ return () => window.removeEventListener("resize", handleResize);
55
+ }, useEffectOnlyOnMount);
56
+ return windowSize;
57
+ }
58
+ export function useElementSize(elm: HTMLElement) {
59
+ // Initialize state with undefined width/height so server and client renders match
60
+ // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
61
+ const [elmSize, setELmSize] = useState<{
62
+ width: number,
63
+ height: number
64
+ }>({
65
+ width: undefined,
66
+ height: undefined
67
+ });
68
+ useEffect(() => {
69
+ if (elm) {
70
+ // Handler to call on elm resize
71
+ function handleResize() {
72
+ // Set elm width/height to state
73
+ setELmSize({
74
+ width: (elm instanceof Window) ? elm.innerWidth : elm.clientWidth,
75
+ height: (elm instanceof Window) ? elm.innerHeight : elm.clientHeight,
76
+ });
77
+ }
78
+ // Add event listener
79
+ const observer = new ResizeObserver(handleResize);
80
+ observer.observe(elm);
81
+ // Call handler right away so state gets updated with initial elm size
82
+ handleResize();
83
+ // Remove event listener on cleanup
84
+ return () => observer.disconnect();
85
+ }
86
+ }, [elm]);
87
+ return elmSize;
88
+ }
89
+ export function useIsInPrint() {
90
+ // Initialize state with false
91
+ const [printMode, setPrintMode] = useState<boolean>(false);
92
+ useEffect(() => {
93
+ function forcePrint(e: KeyboardEvent) {
94
+ if (e.ctrlKey && e.shiftKey && e.altKey) {
95
+ if (e.key.toLocaleLowerCase() === "q") {
96
+ document.body.classList.remove(KnownClassNames.print);
97
+ handlePrint(e, false);
98
+ }
99
+ else {
100
+ console.warn('forced print mode - to exit refresh to ctrl+shift+alt+q');
101
+ document.body.classList.add(KnownClassNames.print);
102
+ handlePrint(e, true);
103
+ }
104
+ }
105
+ }
106
+ // Handler to call on printing
107
+ function handlePrint(e?: Event, force?: boolean) {
108
+ if (force === true) setPrintMode(true);
109
+ else if (window.matchMedia) {
110
+ var mediaQueryList = window.matchMedia('print');
111
+ if (mediaQueryList.matches) {
112
+ setPrintMode(true);
113
+ } else {
114
+ setPrintMode(false);
115
+ }
116
+ }
117
+ }
118
+ // Add event listener
119
+ window.addEventListener("print", handlePrint);
120
+ if (isDebug())
121
+ window.addEventListener("keydown", forcePrint);
122
+ // Call handler right away so state gets updated with initial printing state
123
+ handlePrint();
124
+ // Remove event listener on cleanup
125
+ return () => {
126
+ window.removeEventListener("print", handlePrint);
127
+ if (isDebug())
128
+ window.removeEventListener("keydown", forcePrint);
129
+ };
130
+ }, useEffectOnlyOnMount);
131
+ return printMode;
132
+ }
133
+
134
+ export function useKeyDown(options: {
135
+ //default use document
136
+ elm?: HTMLElement | Document;
137
+ onEnter?: (e: KeyboardEvent) => void;
138
+ onEscape?: (e: KeyboardEvent) => void;
139
+ onKeyDown?: (e: KeyboardEvent) => void;
140
+ }) {
141
+ let elm = options.elm || document;
142
+
143
+ useEffect(() => {
144
+ let handler = (e: KeyboardEvent) => {
145
+ if (e.key === "Enter" && isFunction(options.onEnter)) options.onEnter(e);
146
+ else if (e.key === "Escape" && isFunction(options.onEscape)) options.onEscape(e);
147
+ if (isFunction(options.onKeyDown))
148
+ options.onKeyDown(e);
149
+ };
150
+ elm.addEventListener("keydown", handler);
151
+ return () => elm.removeEventListener("keydown", handler);
152
+ }, [elm, options.onEnter, options.onEscape, options.onKeyDown]);
153
+ }