@mackin.com/styleguide 7.1.0 → 7.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +33 -1
  2. package/index.js +106 -5
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -349,6 +349,9 @@ interface InputProps {
349
349
  onChange?: (value: InputValue, name?: string) => void;
350
350
  onFocus?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
351
351
  onBlur?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
352
+ onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
353
+ onKeyUp?: (event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
354
+ onKeyPress?: (event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
352
355
  /** Defaults to 100. Ignored for type=number and type=date. */
353
356
  maxLength?: number;
354
357
  /** Ignored for type=textarea. */
@@ -901,4 +904,33 @@ declare const Backdrop: (p: {
901
904
 
902
905
  declare const useMediaQuery: (query: string) => boolean;
903
906
 
904
- export { Alignment, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, ButtonProps, Calendar, CalendarProps, Checkbox, CheckboxProps, ConfirmModal, ConfirmModalProps, CopyButton, DatePicker, DatePickerProps, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, GlobalStyles, Header, Highlight, ICONS, Icon, Image, InfoPanel, InfoTip, InfoTipProps, Input, InputProps, ItemPager, Label, LabelProps, List, ListItem, MackinTheme, Modal, Nav, OmniLink, OmniLinkProps, PagedResult, Pager, PagerProps, Picker, PickerProps, Popover, ProgressBar, ProgressBarProps, SearchBox, SearchBoxProps, Slider, TabHeader, TabHeaderProps, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextProps, Th, ThSort, ThemeProvider, ToggleButton, ToggleButtonGroup, ToggleButtonGroupProps, ToggleButtonProps, TogglePasswordInput, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, getCurrencyDisplay, mergeClassNames, useMediaQuery, useThemeSafely };
907
+ interface AutoCompleteItem {
908
+ id: string | number;
909
+ name: string;
910
+ }
911
+ declare type AutocompleteValue = string | AutoCompleteItem;
912
+ interface AutocompleteProps {
913
+ value: AutocompleteValue | undefined;
914
+ round?: boolean;
915
+ rounded?: boolean;
916
+ rightControl?: JSX.Element;
917
+ placeholder?: string;
918
+ id?: string;
919
+ disabled?: boolean;
920
+ className?: string;
921
+ inputClassName?: string;
922
+ /** If not set, defaults to 100 */
923
+ maxLength?: number;
924
+ required?: boolean;
925
+ /** Limits what will be show in the autocomplete options. Default is 7. */
926
+ maxShownValues?: number;
927
+ /** The minimum characters before 'getOptions' is called. No default. */
928
+ minChars?: number;
929
+ onChange: (value: string) => void;
930
+ getOptions: (value: string) => Promise<AutocompleteValue[]>;
931
+ onPick: (value: AutocompleteValue) => void;
932
+ onKeyPress?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
933
+ }
934
+ declare const Autocomplete: (p: AutocompleteProps) => JSX.Element;
935
+
936
+ export { Alignment, Autocomplete, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, ButtonProps, Calendar, CalendarProps, Checkbox, CheckboxProps, ConfirmModal, ConfirmModalProps, CopyButton, DatePicker, DatePickerProps, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, GlobalStyles, Header, Highlight, ICONS, Icon, Image, InfoPanel, InfoTip, InfoTipProps, Input, InputProps, ItemPager, Label, LabelProps, List, ListItem, MackinTheme, Modal, Nav, OmniLink, OmniLinkProps, PagedResult, Pager, PagerProps, Picker, PickerProps, Popover, ProgressBar, ProgressBarProps, SearchBox, SearchBoxProps, Slider, TabHeader, TabHeaderProps, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextProps, Th, ThSort, ThemeProvider, ToggleButton, ToggleButtonGroup, ToggleButtonGroupProps, ToggleButtonProps, TogglePasswordInput, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, getCurrencyDisplay, mergeClassNames, useMediaQuery, useThemeSafely };
package/index.js CHANGED
@@ -2035,10 +2035,10 @@ const Input = React__namespace.forwardRef((props, ref) => {
2035
2035
  if (props.type === 'number') {
2036
2036
  inputElement = React__namespace.createElement("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly,
2037
2037
  // set fixed default to defeat pasting stupid numbers
2038
- maxLength: 50, min: props.min, max: props.max, required: props.required, disabled: props.disabled, id: props.id, className: css.cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: "number", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
2038
+ maxLength: 50, min: props.min, max: props.max, required: props.required, disabled: props.disabled, id: props.id, className: css.cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: "number", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress });
2039
2039
  }
2040
2040
  else if (props.type === 'date') {
2041
- inputElement = React__namespace.createElement("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: 10, required: props.required, disabled: props.disabled, id: props.id, className: css.cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: "text", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
2041
+ inputElement = React__namespace.createElement("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: 10, required: props.required, disabled: props.disabled, id: props.id, className: css.cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: "text", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress });
2042
2042
  }
2043
2043
  else if (props.type === 'textarea') {
2044
2044
  inputElement = React__namespace.createElement("textarea", { ref: ref, name: props.name, style: props.style, rows: props.rows || 10, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, className: css.cx(css.css `
@@ -2046,11 +2046,11 @@ const Input = React__namespace.forwardRef((props, ref) => {
2046
2046
  max-width: 100%;
2047
2047
  min-height: ${theme.controls.height};
2048
2048
  padding-top: 0.75rem;
2049
- height:auto;`, props.inputClassName), placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
2049
+ height:auto;`, props.inputClassName), placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress });
2050
2050
  }
2051
2051
  else {
2052
2052
  // text, password, email, and url
2053
- inputElement = React__namespace.createElement("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, className: css.cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: props.type, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
2053
+ inputElement = React__namespace.createElement("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, className: css.cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: props.type, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress });
2054
2054
  }
2055
2055
  const inputWrapperStyles = css.css `
2056
2056
  width:100%;
@@ -2972,6 +2972,15 @@ const FileUploader = (p) => {
2972
2972
  maxBytes: p.maxBytes
2973
2973
  });
2974
2974
  };
2975
+ let infoMessage;
2976
+ if (p.infoMessage) {
2977
+ if (typeof p.infoMessage === 'string') {
2978
+ infoMessage = React__default['default'].createElement(Text, { noPad: true }, p.infoMessage);
2979
+ }
2980
+ else {
2981
+ infoMessage = p.infoMessage;
2982
+ }
2983
+ }
2975
2984
  return (React__default['default'].createElement(Form, { ref: form, className: css.css({
2976
2985
  border: theme.controls.border,
2977
2986
  borderStyle: 'dashed',
@@ -3047,11 +3056,11 @@ const FileUploader = (p) => {
3047
3056
  !(files === null || files === void 0 ? void 0 : files.length) && React__default['default'].createElement(Icon, { style: { fontSize: '2rem' }, id: "upload" }),
3048
3057
  React__default['default'].createElement(Text, { align: "center", noPad: true, spacedOut: true },
3049
3058
  filesDisplay,
3050
- p.infoMessage && (React__default['default'].createElement("div", null, p.infoMessage)),
3051
3059
  !!(files === null || files === void 0 ? void 0 : files.length) && (React__default['default'].createElement(Button, { onClick: e => {
3052
3060
  e.stopPropagation();
3053
3061
  onFilesChange(undefined);
3054
3062
  }, className: css.css({ marginLeft: '1rem', color: theme.colors.negative }), rightIcon: React__default['default'].createElement(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear"))),
3063
+ infoMessage,
3055
3064
  !!(files === null || files === void 0 ? void 0 : files.invalidFiles.length) && (React__default['default'].createElement(InfoPanel, { variant: "error" },
3056
3065
  "Invalid files: ",
3057
3066
  files.invalidFiles.map(f => f.name).join(', '),
@@ -3349,6 +3358,98 @@ const Backdrop = (props) => {
3349
3358
  }, ref: backdrop, className: css.cx('backdrop', styles, props.className) }, props.children));
3350
3359
  };
3351
3360
 
3361
+ const DEFAULT_MAX_SHOWN_VALUES = 7;
3362
+ const getAutocompleteValueText = (v) => {
3363
+ if (!v) {
3364
+ return '';
3365
+ }
3366
+ if (typeof v === 'string') {
3367
+ return v;
3368
+ }
3369
+ return v.name;
3370
+ };
3371
+ const getAutocompleteValueId = (v) => {
3372
+ if (typeof v === 'string') {
3373
+ return v;
3374
+ }
3375
+ return v.id;
3376
+ };
3377
+ const Autocomplete = (p) => {
3378
+ const element = React__namespace.useRef(null);
3379
+ const input = React__namespace.useRef(null);
3380
+ const [values, setValues] = React__namespace.useState([]);
3381
+ const showValues = React__namespace.useMemo(() => values.length > 0, [values]);
3382
+ const shownValues = React__namespace.useMemo(() => {
3383
+ var _a;
3384
+ return values.slice(0, (_a = p.maxShownValues) !== null && _a !== void 0 ? _a : DEFAULT_MAX_SHOWN_VALUES);
3385
+ }, [values]);
3386
+ const theme = useThemeSafely();
3387
+ const baseClass = css.css `
3388
+ label: Autocomplete;
3389
+ position: relative;
3390
+ width: 100%;
3391
+ `;
3392
+ const listClass = css.css `
3393
+ position: absolute;
3394
+ width: 100%;
3395
+ border: ${theme.controls.border};
3396
+ box-shadow: ${theme.controls.boxShadow};
3397
+ background-color: ${theme.colors.bg};
3398
+ margin-top: -4px !important;
3399
+ z-index: ${theme.zIndexes.backdrop};
3400
+ ${p.round || p.rounded && `
3401
+ border-radius: ${theme.controls.roundedRadius};
3402
+ `}
3403
+ `;
3404
+ const inputClass = css.css `
3405
+ ${showValues && `
3406
+ z-index: ${theme.zIndexes.backdrop};
3407
+ position: relative;
3408
+ `}
3409
+ `;
3410
+ return (React__namespace.createElement("div", { ref: element, className: css.cx(baseClass, 'autocomplete') },
3411
+ React__namespace.createElement(Backdrop, { onClick: () => setValues([]), show: showValues, allowScroll: true, transparent: true }),
3412
+ React__namespace.createElement(TabLocker, { disabled: !showValues, style: { position: 'relative' } },
3413
+ React__namespace.createElement(Input, { ref: input, debounceMs: 0, type: "text", value: getAutocompleteValueText(p.value), round: p.round, rounded: p.rounded, rightControl: p.rightControl, placeholder: p.placeholder, id: p.id, disabled: p.disabled, className: p.className, inputClassName: css.cx(inputClass, p.inputClassName), maxLength: p.maxLength, required: p.required, onChange: v => {
3414
+ const value = v;
3415
+ p.onChange(value);
3416
+ if (!p.minChars || value.length >= p.minChars) {
3417
+ p.getOptions(value)
3418
+ .then(vals => {
3419
+ setValues(vals);
3420
+ }).catch(err => {
3421
+ // ignore it
3422
+ });
3423
+ }
3424
+ else {
3425
+ setValues([]);
3426
+ }
3427
+ }, onKeyPress: e => { var _a; return (_a = p.onKeyPress) === null || _a === void 0 ? void 0 : _a.call(p, e); } }),
3428
+ showValues && (React__namespace.createElement(List, { className: listClass },
3429
+ shownValues.map(value => {
3430
+ return (React__namespace.createElement(ListItem, { key: getAutocompleteValueId(value), variant: "full" },
3431
+ React__namespace.createElement(Button, { onClick: () => {
3432
+ p.onPick(value);
3433
+ setValues([]);
3434
+ setTimeout(() => {
3435
+ var _a;
3436
+ // we need to wait until the component is re-rendered.
3437
+ // outside changes to Inputs will be ignored if the component has focus.
3438
+ (_a = input.current) === null || _a === void 0 ? void 0 : _a.focus();
3439
+ }, 0);
3440
+ } },
3441
+ React__namespace.createElement(Text, { tag: "div", ellipsis: true, align: "left" }, getAutocompleteValueText(value)))));
3442
+ }),
3443
+ shownValues.length < values.length && (React__namespace.createElement(ListItem, null,
3444
+ React__namespace.createElement(Text, { tag: "div", italics: true, align: "center" },
3445
+ "Showing ",
3446
+ shownValues.length.toLocaleString(),
3447
+ " of ",
3448
+ values.length.toLocaleString(),
3449
+ " results."))))))));
3450
+ };
3451
+
3452
+ exports.Autocomplete = Autocomplete;
3352
3453
  exports.Backdrop = Backdrop;
3353
3454
  exports.Backdrop2 = Backdrop$1;
3354
3455
  exports.BoundMemoryPager = BoundMemoryPager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mackin.com/styleguide",
3
- "version": "7.1.0",
3
+ "version": "7.2.1",
4
4
  "description": "",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",