@kwiz/fluentui 1.0.57 → 1.0.60

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.
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
+ }