@culturehq/add-to-calendar
Advanced tools
Comparing version 0.2.0 to 1.0.0
@@ -9,2 +9,10 @@ # Changelog | ||
## [1.0.0] - 2019-03-12 | ||
### Added | ||
- Properly handles focus by focusing on the first link when the dropdown is rendered and then passing it back to the previous active element when the dropdown is hidden. | ||
- Keyboard handling on the dropdown to allow the user to hit escape to close it. | ||
### Changed | ||
- Rewrote the state management using hooks (and updated the `react` and `react-dom` dependencies to require 16.8). | ||
## [0.2.0] - 2018-12-19 | ||
@@ -18,4 +26,5 @@ ### Changed | ||
[Unreleased]: https://github.com/CultureHQ/add-to-calendar/compare/0.2.0...HEAD | ||
[Unreleased]: https://github.com/CultureHQ/add-to-calendar/compare/v1.0.0...HEAD | ||
[1.0.0]: https://github.com/CultureHQ/add-to-calendar/compare/v0.2.0...v1.0.0 | ||
[0.2.0]: https://github.com/CultureHQ/add-to-calendar/compare/v0.1.0...v0.2.0 | ||
[0.1.0]: https://github.com/CultureHQ/add-to-calendar/compare/d105a7...v0.1.0 |
@@ -10,72 +10,58 @@ "use strict"; | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } | ||
var _makeUrls = _interopRequireDefault(require("./makeUrls")); | ||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } | ||
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } | ||
function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } | ||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } | ||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
var makeTime = function makeTime(time) { | ||
return new Date(time).toISOString().replace(/[-:]|\.\d{3}/g, ""); | ||
var useAutoFocus = function useAutoFocus() { | ||
var ref = (0, _react.useRef)(null); | ||
(0, _react.useEffect)(function () { | ||
var _document = document, | ||
activeElement = _document.activeElement; | ||
ref.current.focus(); | ||
return function () { | ||
return activeElement.focus(); | ||
}; | ||
}, []); | ||
return ref; | ||
}; | ||
var makeUrl = function makeUrl(base, query) { | ||
return Object.keys(query).reduce(function (accum, key, index) { | ||
return "".concat(accum).concat(index === 0 ? "?" : "&").concat(key, "=").concat(encodeURIComponent(query[key])); | ||
}, base); | ||
}; | ||
var useOpenState = function useOpenState(initialOpen) { | ||
var _useState = (0, _react.useState)(initialOpen), | ||
_useState2 = _slicedToArray(_useState, 2), | ||
open = _useState2[0], | ||
setOpen = _useState2[1]; | ||
var makeGoogleCalendarUrl = function makeGoogleCalendarUrl(event) { | ||
return makeUrl("https://calendar.google.com/calendar/render", { | ||
action: "TEMPLATE", | ||
dates: "".concat(makeTime(event.startsAt), "/").concat(makeTime(event.endsAt)), | ||
location: event.location, | ||
text: event.name, | ||
details: event.details | ||
}); | ||
}; | ||
var onToggle = (0, _react.useCallback)(function () { | ||
return setOpen(function (current) { | ||
return !current; | ||
}); | ||
}, [setOpen]); | ||
(0, _react.useEffect)(function () { | ||
if (open) { | ||
var onClose = function onClose() { | ||
return setOpen(false); | ||
}; | ||
var makeOutlookCalendarUrl = function makeOutlookCalendarUrl(event) { | ||
return makeUrl("https://outlook.live.com/owa", { | ||
rru: "addevent", | ||
startdt: makeTime(event.startsAt), | ||
enddt: makeTime(event.endsAt), | ||
subject: event.name, | ||
location: event.location, | ||
body: event.details, | ||
allday: false, | ||
uid: new Date().getTime().toString(), | ||
path: "/calendar/view/Month" | ||
}); | ||
}; | ||
document.addEventListener("click", onClose); | ||
return function () { | ||
return document.removeEventListener("click", onClose); | ||
}; | ||
} | ||
var makeYahooCalendarUrl = function makeYahooCalendarUrl(event) { | ||
var minutes = Math.floor((+new Date(event.endsAt) - +new Date(event.startsAt)) / 60 / 1000); | ||
var duration = "".concat(Math.floor(minutes / 60), ":").concat("0".concat(minutes % 60).slice(-2)); | ||
return makeUrl("https://calendar.yahoo.com", { | ||
v: 60, | ||
view: "d", | ||
type: 20, | ||
title: event.name, | ||
st: makeTime(event.startsAt), | ||
dur: duration, | ||
desc: event.details, | ||
in_loc: event.location | ||
}); | ||
return undefined; | ||
}, [open, setOpen]); | ||
return [open, onToggle]; | ||
}; | ||
var Calendar = function Calendar(_ref) { | ||
var Calendar = _react.default.forwardRef(function (_ref, ref) { | ||
var children = _ref.children, | ||
@@ -86,2 +72,3 @@ _ref$download = _ref.download, | ||
return _react.default.createElement("a", { | ||
ref: ref, | ||
download: download, | ||
@@ -92,118 +79,68 @@ href: href, | ||
}, children); | ||
}; | ||
}); | ||
var ICSCalendar = function ICSCalendar(_ref2) { | ||
var children = _ref2.children, | ||
event = _ref2.event; | ||
var components = ["BEGIN:VCALENDAR", "VERSION:2.0", "BEGIN:VEVENT", "URL:".concat(document.URL), "DTSTART:".concat(makeTime(event.startsAt)), "DTEND:".concat(makeTime(event.endsAt)), "SUMMARY:".concat(event.name), "DESCRIPTION:".concat(event.details), "LOCATION:".concat(event.location), "END:VEVENT", "END:VCALENDAR"]; | ||
var href = encodeURI("data:text/calendar;charset=utf8,".concat(components.join("\n"))); | ||
return _react.default.createElement(Calendar, { | ||
href: href, | ||
var Dropdown = function Dropdown(_ref2) { | ||
var onToggle = _ref2.onToggle, | ||
urls = _ref2.urls; | ||
var ref = useAutoFocus(); | ||
var onKeyDown = (0, _react.useCallback)(function (_ref3) { | ||
var key = _ref3.key; | ||
if (key === "Escape") { | ||
onToggle(); | ||
} | ||
}, [onToggle]); | ||
return _react.default.createElement("div", { | ||
className: "chq-atc--dropdown", | ||
onKeyDown: onKeyDown, | ||
role: "presentation" | ||
}, _react.default.createElement(Calendar, { | ||
href: urls.ics, | ||
download: true, | ||
ref: ref | ||
}, "Apple Calendar"), _react.default.createElement(Calendar, { | ||
href: urls.google | ||
}, "Google"), _react.default.createElement(Calendar, { | ||
href: urls.ics, | ||
download: true | ||
}, children); | ||
}, "Outlook"), _react.default.createElement(Calendar, { | ||
href: urls.outlook | ||
}, "Outlook Web App"), _react.default.createElement(Calendar, { | ||
href: urls.yahoo | ||
}, "Yahoo")); | ||
}; | ||
var AddToCalendar = | ||
/*#__PURE__*/ | ||
function (_PureComponent) { | ||
_inherits(AddToCalendar, _PureComponent); | ||
var AddToCalendar = function AddToCalendar(_ref4) { | ||
var _ref4$children = _ref4.children, | ||
children = _ref4$children === void 0 ? "Add to My Calendar" : _ref4$children, | ||
event = _ref4.event, | ||
initialOpen = _ref4.open; | ||
function AddToCalendar(props) { | ||
var _this; | ||
var _useOpenState = useOpenState(initialOpen), | ||
_useOpenState2 = _slicedToArray(_useOpenState, 2), | ||
open = _useOpenState2[0], | ||
onToggle = _useOpenState2[1]; | ||
_classCallCheck(this, AddToCalendar); | ||
var urls = (0, _react.useMemo)(function () { | ||
return (0, _makeUrls.default)(event); | ||
}, [event]); | ||
return _react.default.createElement("div", { | ||
className: "chq-atc" | ||
}, event && _react.default.createElement("button", { | ||
type: "button", | ||
className: "chq-atc--button", | ||
onClick: onToggle | ||
}, _react.default.createElement("svg", { | ||
width: "20px", | ||
height: "20px", | ||
viewBox: "0 0 1024 1024" | ||
}, _react.default.createElement("path", { | ||
d: "M704 192v-64h-32v64h-320v-64h-32v64h-192v704h768v-704h-192z M864 864h-704v-480h704v480z M864 352h-704v-128h160v64h32v-64h320v64h32v-64h160v128z" | ||
})), " ", children), open && _react.default.createElement(Dropdown, { | ||
onToggle: onToggle, | ||
urls: urls | ||
})); | ||
}; | ||
_this = _possibleConstructorReturn(this, _getPrototypeOf(AddToCalendar).call(this, props)); | ||
_this.state = { | ||
open: props.open || false | ||
}; | ||
_this.handleToggle = _this.handleToggle.bind(_assertThisInitialized(_assertThisInitialized(_this))); | ||
return _this; | ||
} | ||
_createClass(AddToCalendar, [{ | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
this.componentIsMounted = true; | ||
this.configureListener(); | ||
} | ||
}, { | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
var open = this.state.open; | ||
if (open !== prevState.open) { | ||
this.configureListener(); | ||
} | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
this.componentIsMounted = false; | ||
} | ||
}, { | ||
key: "configureListener", | ||
value: function configureListener() { | ||
var open = this.state.open; | ||
if (open) { | ||
document.addEventListener("click", this.handleToggle); | ||
} else { | ||
document.removeEventListener("click", this.handleToggle); | ||
} | ||
} | ||
}, { | ||
key: "handleToggle", | ||
value: function handleToggle() { | ||
if (this.componentIsMounted) { | ||
this.setState(function (_ref3) { | ||
var open = _ref3.open; | ||
return { | ||
open: !open | ||
}; | ||
}); | ||
} | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
event = _this$props.event; | ||
var open = this.state.open; | ||
return _react.default.createElement("div", { | ||
className: "chq-atc" | ||
}, event && _react.default.createElement("button", { | ||
type: "button", | ||
className: "chq-atc--button", | ||
onClick: this.handleToggle | ||
}, _react.default.createElement("svg", { | ||
width: "20px", | ||
height: "20px", | ||
viewBox: "0 0 1024 1024" | ||
}, _react.default.createElement("path", { | ||
d: "M704 192v-64h-32v64h-320v-64h-32v64h-192v704h768v-704h-192z M864 864h-704v-480h704v480z M864 352h-704v-128h160v64h32v-64h320v64h32v-64h160v128z" | ||
})), " ", children), open && _react.default.createElement("div", { | ||
className: "chq-atc--dropdown" | ||
}, _react.default.createElement(ICSCalendar, { | ||
event: event | ||
}, "Apple Calendar"), _react.default.createElement(Calendar, { | ||
href: makeGoogleCalendarUrl(event) | ||
}, "Google"), _react.default.createElement(ICSCalendar, { | ||
event: event | ||
}, "Outlook"), _react.default.createElement(Calendar, { | ||
href: makeOutlookCalendarUrl(event) | ||
}, "Outlook Web App"), _react.default.createElement(Calendar, { | ||
href: makeYahooCalendarUrl(event) | ||
}, "Yahoo"))); | ||
} | ||
}]); | ||
return AddToCalendar; | ||
}(_react.PureComponent); | ||
AddToCalendar.defaultProps = { | ||
children: "Add to My Calendar" | ||
}; | ||
var _default = AddToCalendar; | ||
exports.default = _default; |
{ | ||
"name": "@culturehq/add-to-calendar", | ||
"version": "0.2.0", | ||
"version": "1.0.0", | ||
"description": "A small package for adding an event to a calendar.", | ||
@@ -25,32 +25,30 @@ "main": "dist/AddToCalendar.js", | ||
"peerDependencies": { | ||
"react": "^16", | ||
"react-dom": "^16" | ||
"react": ">= 16.8", | ||
"react-dom": ">= 16.8" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.2.0", | ||
"@babel/core": "^7.2.2", | ||
"@babel/preset-env": "^7.2.0", | ||
"@babel/cli": "^7.2.3", | ||
"@babel/core": "^7.3.4", | ||
"@babel/preset-env": "^7.3.4", | ||
"@babel/preset-react": "^7.0.0", | ||
"@culturehq/eslint-config": "^0.2.0", | ||
"@culturehq/eslint-config": "^1.0.0", | ||
"babel-core": "^7.0.0-0", | ||
"babel-eslint": "^10.0.1", | ||
"babel-jest": "^23.6.0", | ||
"babel-loader": "^8.0.4", | ||
"css-loader": "^2.0.1", | ||
"eslint": "^5.10.0", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-jsx-a11y": "^6.1.2", | ||
"eslint-plugin-react": "^7.11.0", | ||
"jest": "^23.6.0", | ||
"react": "^16.7.0-alpha.2", | ||
"react-dom": "^16.7.0-alpha.2", | ||
"react-testing-library": "^5.4.1", | ||
"babel-jest": "^24.5.0", | ||
"babel-loader": "^8.0.5", | ||
"css-loader": "^2.1.1", | ||
"eslint": "^5.15.1", | ||
"jest": "^24.5.0", | ||
"react": "^16.8.4", | ||
"react-dom": "^16.8.4", | ||
"react-testing-library": "^6.0.0", | ||
"style-loader": "^0.23.0", | ||
"webpack": "^4.28.0", | ||
"webpack-cli": "^3.1.0", | ||
"webpack-dev-server": "^3.1.9" | ||
"webpack": "^4.29.6", | ||
"webpack-cli": "^3.2.3", | ||
"webpack-dev-server": "^3.2.1" | ||
}, | ||
"jest": { | ||
"setupTestFrameworkScriptFile": "./setupTests.js" | ||
"setupFilesAfterEnv": [ | ||
"./setupTests.js" | ||
] | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
18
7
240
0
14045