@enact/sandstone
Version:
Large-screen/TV support library for Enact, containing a variety of UI components.
485 lines (473 loc) • 17.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.InputFieldDecorator = exports.InputFieldBase = exports.InputField = void 0;
var _handle = require("@enact/core/handle");
var _kind = _interopRequireDefault(require("@enact/core/kind"));
var _platform = _interopRequireDefault(require("@enact/core/platform"));
var _I18nDecorator = require("@enact/i18n/I18nDecorator");
var _util = require("@enact/i18n/util");
var _AnnounceDecorator = require("@enact/ui/AnnounceDecorator");
var _Changeable = _interopRequireDefault(require("@enact/ui/Changeable"));
var _Pure = _interopRequireDefault(require("@enact/ui/internal/Pure"));
var _speech = require("@enact/webos/speech");
var _classnames2 = _interopRequireDefault(require("classnames"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _compose = _interopRequireDefault(require("ramda/src/compose"));
var _react = require("react");
var _$L = _interopRequireDefault(require("../internal/$L"));
var _Skinnable = _interopRequireDefault(require("../Skinnable"));
var _Tooltip = _interopRequireDefault(require("../TooltipDecorator/Tooltip"));
var _util2 = require("../internal/util");
var _InputFieldDecoratorIcon = _interopRequireDefault(require("./InputFieldDecoratorIcon"));
var _InputFieldSpotlightDecorator = _interopRequireDefault(require("./InputFieldSpotlightDecorator"));
var _util3 = require("./util");
var _InputFieldModule = _interopRequireDefault(require("./InputField.module.css"));
var _jsxRuntime = require("react/jsx-runtime");
var _excluded = ["css", "dir", "disabled", "iconAfter", "iconBefore", "invalidTooltip", "onChange", "placeholder", "size", "type", "value"];
/**
* A Sandstone styled input component.
*
* It supports start and end icons but it does not support Spotlight. Apps should use
* {@link sandstone/Input.InputField}.
*
* @class InputFieldBase
* @memberof sandstone/Input
* @ui
* @public
*/
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
var InputFieldBase = exports.InputFieldBase = (0, _kind["default"])({
name: 'InputField',
propTypes: /** @lends sandstone/Input.InputFieldBase.prototype */{
/**
* Passed by AnnounceDecorator for accessibility.
*
* @type {Function}
* @public
*/
announce: _propTypes["default"].func,
/**
* Customizes the component by mapping the supplied collection of CSS class names to the
* corresponding internal elements and states of this component.
*
* The following classes are supported:
*
* * `inputField` - The root class name
* * `input` - The <input> class name
* * `inputHighlight` - The class used to make input text appear highlighted when `.inputField` has focus, but not `.input`
* * `tooltip` - The "invalid" tooltip
* * `tooltipLabel` - The "invalid" tooltip's label
*
* @type {Object}
* @private
*/
css: _propTypes["default"].object,
// TODO: Document voice control props and make public
'data-webos-voice-group-label': _propTypes["default"].string,
'data-webos-voice-intent': _propTypes["default"].string,
'data-webos-voice-label': _propTypes["default"].string,
/**
* Disables InputField and becomes non-interactive.
*
* @type {Boolean}
* @default false
* @public
*/
disabled: _propTypes["default"].bool,
/**
* Blurs the input when the "enter" key is pressed.
*
* @type {Boolean}
* @default false
* @public
*/
dismissOnEnter: _propTypes["default"].bool,
/**
* The icon to be placed at the end of the input.
*
* @see {@link sandstone/Icon.Icon}
* @type {String}
* @public
*/
iconAfter: _propTypes["default"].string,
/**
* The icon to be placed at the beginning of the input.
*
* @see {@link sandstone/Icon.Icon}
* @type {String}
* @public
*/
iconBefore: _propTypes["default"].string,
/**
* Indicates {@link sandstone/Input.InputFieldBase.value|value} is invalid and shows
* {@link sandstone/Input.InputFieldBase.invalidMessage|invalidMessage}, if set.
*
* @type {Boolean}
* @default false
* @public
*/
invalid: _propTypes["default"].bool,
/**
* The tooltip text to be displayed when the input is
* {@link sandstone/Input.InputFieldBase.invalid|invalid}.
*
* If this value is *falsy*, the tooltip will be shown with the default message.
*
* @type {String}
* @default 'Please enter a valid value.'
* @public
*/
invalidMessage: _propTypes["default"].string,
/**
* Called before the input value is changed.
*
* The change can be prevented by calling `preventDefault` on the event.
*
* @type {Function}
* @public
*/
onBeforeChange: _propTypes["default"].func,
/**
* Called when blurred.
*
* @type {Function}
* @param {Object} event
* @public
*/
onBlur: _propTypes["default"].func,
/**
* Called when the input value is changed.
*
* The event payload includes the current `value` as well as a `stopPropagation()` method
* which may be called to stop the original `onChange` event from the `<input>` from
* bubbling.
*
* @type {Function}
* @param {Object} event
* @public
*/
onChange: _propTypes["default"].func,
/**
* Called when clicked.
*
* @type {Function}
* @param {Object} event
* @public
*/
onClick: _propTypes["default"].func,
/**
* Called when focused.
*
* @type {Function}
* @param {Object} event
* @public
*/
onFocus: _propTypes["default"].func,
/**
* Called when a key is pressed down.
*
* @type {Function}
* @param {Object} event
* @public
*/
onKeyDown: _propTypes["default"].func,
/**
* Text to display when {@link sandstone/Input.InputFieldBase.value|value} is not set.
*
* @type {String}
* @default ''
* @public
*/
placeholder: _propTypes["default"].string,
/**
* Indicates the content's text direction is right-to-left.
*
* @type {Boolean}
* @private
*/
rtl: _propTypes["default"].bool,
/**
* The size of the input field.
*
* @type {('large'|'small')}
* @default 'small'
* @public
*/
size: _propTypes["default"].oneOf(['small', 'large']),
/**
* The type of input.
*
* Accepted values correspond to the standard HTML5 input types.
*
* @type {String}
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Form_%3Cinput%3E_types|MDN input types doc}
* @default 'text'
* @public
*/
type: _propTypes["default"].string,
/**
* The value of the input.
*
* @type {String|Number}
* @public
*/
value: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].number])
},
defaultProps: {
disabled: false,
dismissOnEnter: false,
invalid: false,
placeholder: '',
size: 'small',
type: 'text'
},
styles: {
css: _InputFieldModule["default"],
className: 'inputField',
publicClassNames: ['inputField', 'input', 'inputHighlight', 'tooltip', 'tooltipLabel']
},
handlers: {
onChange: (0, _handle.handle)((0, _handle.forwardCustomWithPrevent)('onBeforeChange', function (ev) {
return {
value: ev.target.value
};
}), (0, _handle.returnsTrue)(function (ev, _ref) {
var announce = _ref.announce,
type = _ref.type;
if (type === 'passwordtel') {
if (_platform["default"].type === 'webos') {
(0, _speech.readAlert)((0, _$L["default"])('hidden'));
} else {
announce((0, _$L["default"])('hidden'));
}
}
}), (0, _handle.forwardCustom)('onChange', function (ev) {
return {
value: ev.target.value
};
}))
},
computed: {
'aria-label': function ariaLabel(_ref2) {
var placeholder = _ref2.placeholder,
type = _ref2.type,
value = _ref2.value;
var title = value == null || value === '' ? placeholder : '';
return (0, _util3.calcAriaLabel)(title, type, value);
},
className: function className(_ref3) {
var invalid = _ref3.invalid,
size = _ref3.size,
styler = _ref3.styler;
return styler.append({
invalid: invalid
}, size);
},
dir: function dir(_ref4) {
var value = _ref4.value,
placeholder = _ref4.placeholder;
return (0, _util.isRtlText)(value || placeholder) ? 'rtl' : 'ltr';
},
invalidTooltip: function invalidTooltip(_ref5) {
var css = _ref5.css,
invalid = _ref5.invalid,
_ref5$invalidMessage = _ref5.invalidMessage,
invalidMessage = _ref5$invalidMessage === void 0 ? (0, _$L["default"])('Please enter a valid value.') : _ref5$invalidMessage;
if (invalid && invalidMessage) {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip["default"], {
css: css,
marquee: true,
relative: true,
type: "transparent",
children: invalidMessage
});
}
},
// ensure we have a value so the internal <input> is always controlled
value: function value(_ref6) {
var _value = _ref6.value;
return typeof _value === 'number' ? _value : _value || '';
}
},
render: function render(_ref7) {
var css = _ref7.css,
dir = _ref7.dir,
disabled = _ref7.disabled,
iconAfter = _ref7.iconAfter,
iconBefore = _ref7.iconBefore,
invalidTooltip = _ref7.invalidTooltip,
onChange = _ref7.onChange,
placeholder = _ref7.placeholder,
size = _ref7.size,
type = _ref7.type,
value = _ref7.value,
rest = _objectWithoutProperties(_ref7, _excluded);
var inputProps = (0, _util3.extractInputProps)(rest);
var voiceProps = (0, _util2.extractVoiceProps)(rest);
var isPasswordtel = type === 'passwordtel';
if (type === 'password' || type === 'passwordtel') {
inputProps.spellCheck = false;
}
delete rest.announce;
delete rest.dismissOnEnter;
delete rest.invalid;
delete rest.invalidMessage;
delete rest.onBeforeChange;
delete rest.rtl;
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, rest), {}, {
"aria-disabled": disabled,
disabled: disabled,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: css.bg
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_InputFieldDecoratorIcon["default"], {
position: "before",
size: size,
children: iconBefore
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
className: css.inputHighlight,
children: value ? value : placeholder
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("input", _objectSpread(_objectSpread(_objectSpread({}, inputProps), voiceProps), {}, {
"aria-hidden": isPasswordtel,
className: (0, _classnames2["default"])(css.input, _defineProperty({}, css.passwordtel, isPasswordtel)),
dir: dir,
disabled: disabled,
onChange: onChange,
placeholder: placeholder,
tabIndex: -1,
type: isPasswordtel ? 'tel' : type,
value: value
})), /*#__PURE__*/(0, _jsxRuntime.jsx)(_InputFieldDecoratorIcon["default"], {
position: "after",
size: size,
children: iconAfter
}), invalidTooltip]
}));
}
});
// eslint-disable-next-line no-shadow
var AnnounceDecorator = function AnnounceDecorator(Wrapped) {
return function AnnounceDecorator(props) {
var _useAnnounce = (0, _AnnounceDecorator.useAnnounce)(),
announce = _useAnnounce.announce,
children = _useAnnounce.children;
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Wrapped, _objectSpread(_objectSpread({}, props), {}, {
announce: announce
})), children]
});
};
};
/**
* Sandstone specific item behaviors to apply to {@link sandstone/Input.InputFieldBase|InputField}.
*
* @class InputFieldDecorator
* @hoc
* @memberof sandstone/Input
* @mixes ui/Changeable.Changeable
* @mixes sandstone/Skinnable.Skinnable
* @public
*/
var InputFieldDecorator = exports.InputFieldDecorator = (0, _compose["default"])(_Pure["default"], (0, _I18nDecorator.I18nContextDecorator)({
rtlProp: 'rtl'
}), _Changeable["default"], _InputFieldSpotlightDecorator["default"], AnnounceDecorator, _Skinnable["default"]);
/**
* A Spottable, Sandstone styled input component with embedded icon support.
*
* By default, `InputField` maintains the state of its `value` property. Supply the `defaultValue`
* property to control its initial value. If you wish to directly control updates to the component,
* supply a value to `value` at creation time and update it in response to `onChange` events.
*
* @class InputField
* @memberof sandstone/Input
* @extends sandstone/Input.InputFieldBase
* @mixes ui/Changeable.Changeable
* @mixes spotlight/Spottable.Spottable
* @mixes sandstone/Skinnable.Skinnable
* @ui
* @public
*/
var InputField = exports.InputField = InputFieldDecorator(InputFieldBase);
/**
* Focuses the internal input when the component gains 5-way focus.
*
* By default, the internal input is not editable when the component is focused via 5-way and must
* be selected to become interactive. In pointer mode, the input will be editable when clicked.
*
* @name autoFocus
* @memberof sandstone/Input.InputField.prototype
* @type {Boolean}
* @default false
* @public
*/
/**
* Applies a disabled style and prevents interacting with the component.
*
* @name disabled
* @memberof sandstone/Input.InputField.prototype
* @type {Boolean}
* @default false
* @public
*/
/**
* Sets the initial value.
*
* @name defaultValue
* @memberof sandstone/Input.InputField.prototype
* @type {String}
* @public
*/
/**
* Blurs the input when the "enter" key is pressed.
*
* @name dismissOnEnter
* @memberof sandstone/Input.InputField.prototype
* @type {Boolean}
* @default false
* @public
*/
/**
* Called when the internal input is focused.
*
* @name onActivate
* @memberof sandstone/Input.InputField.prototype
* @type {Function}
* @param {Object} event
* @public
*/
/**
* Called when the internal input loses focus.
*
* @name onDeactivate
* @memberof sandstone/Input.InputField.prototype
* @type {Function}
* @param {Object} event
* @public
*/
/**
* Called when the component is removed when it had focus.
*
* @name onSpotlightDisappear
* @memberof sandstone/Input.InputField.prototype
* @type {Function}
* @param {Object} event
* @public
*/
/**
* Disables spotlight navigation into the component.
*
* @name spotlightDisabled
* @memberof sandstone/Input.InputField.prototype
* @type {Boolean}
* @default false
* @public
*/
var _default = exports["default"] = InputField;