__( 'Save as a template', 'elementor' ); __( 'New', 'elementor' ); __( 'Create component', 'elementor' ); __( 'To create new components, update Elementor Pro to the latest version.', 'elementor' ); __( 'Update Now', 'elementor' ); __( 'Add %s', 'elementor' ); __( 'Edit %s', 'elementor' ); __( 'Duplicate %s', 'elementor' ); __( 'Delete %s', 'elementor' );# Members - EDD Integration The Members - EDD Integration add-on more nicely integrates the [Easy Digital Downloads](https://easydigitaldownloads.com/) plugin capabilities into the Members plugin's role manager. The [Members plugin](https://themehybrid.com/plugins/members) and the Easy Digital Downloads plugin are required to be installed and activated for this plugin to work. ## Shop Role Group The plugin creates a new "Shop" role group for Easy Digital Downloads, which is located under the Users > Roles screen in the admin. This role group lists the following roles: - Shop Accountant - Shop Manager - Shop Vendor - Shop Worker - Any other roles that have EDD-related capabilities. This allows you to see any roles that have EDD permissions at a glance. ## Downloads Capability Group When editing or creating a new role in Members, this add-on creates a new "Downloads" tab (cap group). This tab combines all of the Easy Digital Downloads capabilities in one place. That way, you can see all available caps without jumping between different tabs. ## Copyright and License This project is licensed under the [GNU GPL](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html), version 2 or later. 2019 © [Justin Tadlock](http://justintadlock.com). /******/ (function() { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./node_modules/@monaco-editor/loader/lib/es/_virtual/_rollupPluginBabelHelpers.js": /*!*****************************************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/_virtual/_rollupPluginBabelHelpers.js ***! \*****************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ arrayLikeToArray: function() { return /* binding */ _arrayLikeToArray; }, /* harmony export */ arrayWithHoles: function() { return /* binding */ _arrayWithHoles; }, /* harmony export */ defineProperty: function() { return /* binding */ _defineProperty; }, /* harmony export */ iterableToArrayLimit: function() { return /* binding */ _iterableToArrayLimit; }, /* harmony export */ nonIterableRest: function() { return /* binding */ _nonIterableRest; }, /* harmony export */ objectSpread2: function() { return /* binding */ _objectSpread2; }, /* harmony export */ objectWithoutProperties: function() { return /* binding */ _objectWithoutProperties; }, /* harmony export */ objectWithoutPropertiesLoose: function() { return /* binding */ _objectWithoutPropertiesLoose; }, /* harmony export */ slicedToArray: function() { return /* binding */ _slicedToArray; }, /* harmony export */ toPrimitive: function() { return /* binding */ _toPrimitive; }, /* harmony export */ toPropertyKey: function() { return /* binding */ _toPropertyKey; }, /* harmony export */ unsupportedIterableToArray: function() { return /* binding */ _unsupportedIterableToArray; } /* harmony export */ }); function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = true, o = false; try { if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = true, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } 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 _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).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 _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } 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); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/config/index.js": /*!*******************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/config/index.js ***! \*******************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ config; } /* harmony export */ }); var config = { paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs' } }; /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/index.js": /*!************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/index.js ***! \************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* reexport safe */ _loader_index_js__WEBPACK_IMPORTED_MODULE_0__["default"]; } /* harmony export */ }); /* harmony import */ var _loader_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./loader/index.js */ "./node_modules/@monaco-editor/loader/lib/es/loader/index.js"); /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/loader/index.js": /*!*******************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/loader/index.js ***! \*******************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ loader; } /* harmony export */ }); /* harmony import */ var _virtual_rollupPluginBabelHelpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_virtual/_rollupPluginBabelHelpers.js */ "./node_modules/@monaco-editor/loader/lib/es/_virtual/_rollupPluginBabelHelpers.js"); /* harmony import */ var state_local__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! state-local */ "./node_modules/state-local/lib/es/state-local.js"); /* harmony import */ var _config_index_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config/index.js */ "./node_modules/@monaco-editor/loader/lib/es/config/index.js"); /* harmony import */ var _validators_index_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../validators/index.js */ "./node_modules/@monaco-editor/loader/lib/es/validators/index.js"); /* harmony import */ var _utils_compose_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utils/compose.js */ "./node_modules/@monaco-editor/loader/lib/es/utils/compose.js"); /* harmony import */ var _utils_deepMerge_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../utils/deepMerge.js */ "./node_modules/@monaco-editor/loader/lib/es/utils/deepMerge.js"); /* harmony import */ var _utils_makeCancelable_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils/makeCancelable.js */ "./node_modules/@monaco-editor/loader/lib/es/utils/makeCancelable.js"); var _excluded = ["monaco"]; /** the local state of the module */ var _state$create = state_local__WEBPACK_IMPORTED_MODULE_1__["default"].create({ config: _config_index_js__WEBPACK_IMPORTED_MODULE_2__["default"], isInitialized: false, resolve: null, reject: null, monaco: null }), _state$create2 = (0,_virtual_rollupPluginBabelHelpers_js__WEBPACK_IMPORTED_MODULE_0__.slicedToArray)(_state$create, 2), getState = _state$create2[0], setState = _state$create2[1]; /** * set the loader configuration * @param {Object} config - the configuration object */ function config(globalConfig) { var _validators$config = _validators_index_js__WEBPACK_IMPORTED_MODULE_3__["default"].config(globalConfig), monaco = _validators$config.monaco, config = (0,_virtual_rollupPluginBabelHelpers_js__WEBPACK_IMPORTED_MODULE_0__.objectWithoutProperties)(_validators$config, _excluded); setState(function (state) { return { config: (0,_utils_deepMerge_js__WEBPACK_IMPORTED_MODULE_5__["default"])(state.config, config), monaco: monaco }; }); } /** * handles the initialization of the monaco-editor * @return {Promise} - returns an instance of monaco (with a cancelable promise) */ function init() { var state = getState(function (_ref) { var monaco = _ref.monaco, isInitialized = _ref.isInitialized, resolve = _ref.resolve; return { monaco: monaco, isInitialized: isInitialized, resolve: resolve }; }); if (!state.isInitialized) { setState({ isInitialized: true }); if (state.monaco) { state.resolve(state.monaco); return (0,_utils_makeCancelable_js__WEBPACK_IMPORTED_MODULE_6__["default"])(wrapperPromise); } if (window.monaco && window.monaco.editor) { storeMonacoInstance(window.monaco); state.resolve(window.monaco); return (0,_utils_makeCancelable_js__WEBPACK_IMPORTED_MODULE_6__["default"])(wrapperPromise); } (0,_utils_compose_js__WEBPACK_IMPORTED_MODULE_4__["default"])(injectScripts, getMonacoLoaderScript)(configureLoader); } return (0,_utils_makeCancelable_js__WEBPACK_IMPORTED_MODULE_6__["default"])(wrapperPromise); } /** * injects provided scripts into the document.body * @param {Object} script - an HTML script element * @return {Object} - the injected HTML script element */ function injectScripts(script) { return document.body.appendChild(script); } /** * creates an HTML script element with/without provided src * @param {string} [src] - the source path of the script * @return {Object} - the created HTML script element */ function createScript(src) { var script = document.createElement('script'); return src && (script.src = src), script; } /** * creates an HTML script element with the monaco loader src * @return {Object} - the created HTML script element */ function getMonacoLoaderScript(configureLoader) { var state = getState(function (_ref2) { var config = _ref2.config, reject = _ref2.reject; return { config: config, reject: reject }; }); var loaderScript = createScript("".concat(state.config.paths.vs, "/loader.js")); loaderScript.onload = function () { return configureLoader(); }; loaderScript.onerror = state.reject; return loaderScript; } /** * configures the monaco loader */ function configureLoader() { var state = getState(function (_ref3) { var config = _ref3.config, resolve = _ref3.resolve, reject = _ref3.reject; return { config: config, resolve: resolve, reject: reject }; }); var require = window.require; require.config(state.config); require(['vs/editor/editor.main'], function (loaded) { var monaco = loaded.m /* for 0.53 & 0.54 */ || loaded /* for other versions */; storeMonacoInstance(monaco); state.resolve(monaco); }, function (error) { state.reject(error); }); } /** * store monaco instance in local state */ function storeMonacoInstance(monaco) { if (!getState().monaco) { setState({ monaco: monaco }); } } /** * internal helper function * extracts stored monaco instance * @return {Object|null} - the monaco instance */ function __getMonacoInstance() { return getState(function (_ref4) { var monaco = _ref4.monaco; return monaco; }); } var wrapperPromise = new Promise(function (resolve, reject) { return setState({ resolve: resolve, reject: reject }); }); var loader = { config: config, init: init, __getMonacoInstance: __getMonacoInstance }; /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/utils/compose.js": /*!********************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/utils/compose.js ***! \********************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ compose; } /* harmony export */ }); var compose = function compose() { for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { fns[_key] = arguments[_key]; } return function (x) { return fns.reduceRight(function (y, f) { return f(y); }, x); }; }; /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/utils/curry.js": /*!******************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/utils/curry.js ***! \******************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ curry; } /* harmony export */ }); function curry(fn) { return function curried() { var _this = this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return args.length >= fn.length ? fn.apply(this, args) : function () { for (var _len2 = arguments.length, nextArgs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { nextArgs[_key2] = arguments[_key2]; } return curried.apply(_this, [].concat(args, nextArgs)); }; }; } /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/utils/deepMerge.js": /*!**********************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/utils/deepMerge.js ***! \**********************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ merge; } /* harmony export */ }); /* harmony import */ var _virtual_rollupPluginBabelHelpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_virtual/_rollupPluginBabelHelpers.js */ "./node_modules/@monaco-editor/loader/lib/es/_virtual/_rollupPluginBabelHelpers.js"); function merge(target, source) { Object.keys(source).forEach(function (key) { if (source[key] instanceof Object) { if (target[key]) { Object.assign(source[key], merge(target[key], source[key])); } } }); return (0,_virtual_rollupPluginBabelHelpers_js__WEBPACK_IMPORTED_MODULE_0__.objectSpread2)((0,_virtual_rollupPluginBabelHelpers_js__WEBPACK_IMPORTED_MODULE_0__.objectSpread2)({}, target), source); } /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/utils/isObject.js": /*!*********************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/utils/isObject.js ***! \*********************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ isObject; } /* harmony export */ }); function isObject(value) { return {}.toString.call(value).includes('Object'); } /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/utils/makeCancelable.js": /*!***************************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/utils/makeCancelable.js ***! \***************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CANCELATION_MESSAGE: function() { return /* binding */ CANCELATION_MESSAGE; }, /* harmony export */ "default": function() { return /* binding */ makeCancelable; } /* harmony export */ }); // The source (has been changed) is https://github.com/facebook/react/issues/5465#issuecomment-157888325 var CANCELATION_MESSAGE = { type: 'cancelation', msg: 'operation is manually canceled' }; function makeCancelable(promise) { var hasCanceled_ = false; var wrappedPromise = new Promise(function (resolve, reject) { promise.then(function (val) { return hasCanceled_ ? reject(CANCELATION_MESSAGE) : resolve(val); }); promise["catch"](reject); }); return wrappedPromise.cancel = function () { return hasCanceled_ = true; }, wrappedPromise; } /***/ }), /***/ "./node_modules/@monaco-editor/loader/lib/es/validators/index.js": /*!***********************************************************************!*\ !*** ./node_modules/@monaco-editor/loader/lib/es/validators/index.js ***! \***********************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ validators; }, /* harmony export */ errorHandler: function() { return /* binding */ errorHandler; }, /* harmony export */ errorMessages: function() { return /* binding */ errorMessages; } /* harmony export */ }); /* harmony import */ var _utils_curry_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/curry.js */ "./node_modules/@monaco-editor/loader/lib/es/utils/curry.js"); /* harmony import */ var _utils_isObject_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/isObject.js */ "./node_modules/@monaco-editor/loader/lib/es/utils/isObject.js"); /** * validates the configuration object and informs about deprecation * @param {Object} config - the configuration object * @return {Object} config - the validated configuration object */ function validateConfig(config) { if (!config) errorHandler('configIsRequired'); if (!(0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_1__["default"])(config)) errorHandler('configType'); if (config.urls) { informAboutDeprecation(); return { paths: { vs: config.urls.monacoBase } }; } return config; } /** * logs deprecation message */ function informAboutDeprecation() { console.warn(errorMessages.deprecation); } function throwError(errorMessages, type) { throw new Error(errorMessages[type] || errorMessages["default"]); } var errorMessages = { configIsRequired: 'the configuration object is required', configType: 'the configuration object should be an object', "default": 'an unknown error accured in `@monaco-editor/loader` package', deprecation: "Deprecation warning!\n You are using deprecated way of configuration.\n\n Instead of using\n monaco.config({ urls: { monacoBase: '...' } })\n use\n monaco.config({ paths: { vs: '...' } })\n\n For more please check the link https://github.com/suren-atoyan/monaco-loader#config\n " }; var errorHandler = (0,_utils_curry_js__WEBPACK_IMPORTED_MODULE_0__["default"])(throwError)(errorMessages); var validators = { config: validateConfig }; /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-editor.styles.ts": /*!************************************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-editor.styles.ts ***! \************************************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ EditorWrapper: function() { return /* binding */ EditorWrapper; }, /* harmony export */ ResizeHandle: function() { return /* binding */ ResizeHandle; } /* harmony export */ }); /* harmony import */ var _elementor_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/ui */ "@elementor/ui"); /* harmony import */ var _elementor_ui__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_ui__WEBPACK_IMPORTED_MODULE_0__); const EditorWrapper = (0,_elementor_ui__WEBPACK_IMPORTED_MODULE_0__.styled)((0,_elementor_ui__WEBPACK_IMPORTED_MODULE_0__.Box))` /* @noflip */ direction: ltr; border: 1px solid var( --e-a-border-color ); border-radius: 8px; padding: 4px; position: relative; height: 200px; .monaco-editor .suggest-widget { width: 220px !important; max-width: 220px !important; z-index: 1001; } .visual-content-dimmed { opacity: 0.6; color: #aaa !important; pointer-events: none; } .monaco-editor { .margin-view-overlays > div:nth-of-type( 1 ) .cldr.codicon.codicon-folding-expanded { visibility: hidden; } .monaco-scrollable-element { > .scrollbar { width: 6px !important; > .slider { width: 6px !important; } } } } `; const ResizeHandle = (0,_elementor_ui__WEBPACK_IMPORTED_MODULE_0__.styled)((0,_elementor_ui__WEBPACK_IMPORTED_MODULE_0__.Button))` position: absolute; bottom: 0; left: 0; right: 0; height: 6px; cursor: ns-resize; background: transparent; border: none; padding: 0; &:hover { background: rgba( 0, 0, 0, 0.05 ); } &:active { background: rgba( 0, 0, 0, 0.1 ); } &::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate( -50%, -50% ); width: 30px; height: 2px; background: var( --e-a-border-color ); border-radius: 1px; } `; /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-editor.tsx": /*!******************************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-editor.tsx ***! \******************************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CssEditor: function() { return /* binding */ CssEditor; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @elementor/editor-controls */ "@elementor/editor-controls"); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _elementor_editor_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @elementor/editor-ui */ "@elementor/editor-ui"); /* harmony import */ var _elementor_editor_ui__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_ui__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _elementor_ui__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @elementor/ui */ "@elementor/ui"); /* harmony import */ var _elementor_ui__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _monaco_editor_react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @monaco-editor/react */ "./node_modules/@monaco-editor/react/dist/index.mjs"); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n"); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__); /* harmony import */ var _css_editor_styles__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./css-editor.styles */ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-editor.styles.ts"); /* harmony import */ var _css_validation__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./css-validation */ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-validation.ts"); /* harmony import */ var _resize_handle__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./resize-handle */ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/resize-handle.tsx"); /* harmony import */ var _visual_content_change_protection__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./visual-content-change-protection */ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/visual-content-change-protection.ts"); const createEditorDidMountHandler = (editorRef, monacoRef, onUserContentChange, setIsValid, syntaxRuleOptions) => { return (editor, monaco) => { editorRef.current = editor; monacoRef.current = monaco; (0,_visual_content_change_protection__WEBPACK_IMPORTED_MODULE_9__.preventChangeOnVisualContent)(editor); (0,_css_validation__WEBPACK_IMPORTED_MODULE_7__.setCustomSyntaxRules)(editor, monaco, syntaxRuleOptions); const initialCode = editor.getModel()?.getValue() ?? ''; const initialUserContent = (0,_visual_content_change_protection__WEBPACK_IMPORTED_MODULE_9__.getActual)(initialCode); onUserContentChange(initialUserContent); monaco.editor.onDidChangeMarkers(() => { (0,_css_validation__WEBPACK_IMPORTED_MODULE_7__.clearMarkersFromVisualContent)(editor, monaco); setIsValid((0,_css_validation__WEBPACK_IMPORTED_MODULE_7__.validate)(editor, monaco)); }); editor.setPosition({ lineNumber: 2, column: (editor.getModel()?.getLineContent(2).length ?? 0) + 1 }); disableFoldingFirstRow(editor); // eslint-disable-next-line no-bitwise editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyA, () => { const editorModel = editor.getModel(); if (!editorModel) { return; } const fullRange = editorModel.getFullModelRange(); const contentEndLine = fullRange.endLineNumber - 1; let endColumn = editorModel.getLineLastNonWhitespaceColumn(contentEndLine); if (endColumn === 0) { endColumn = editorModel.getLineMaxColumn(contentEndLine); } editor.setSelection(new monaco.Selection(fullRange.startLineNumber + 1, fullRange.startColumn, contentEndLine, endColumn)); }); }; }; function disableFoldingFirstRow(editor) { if (!(typeof editor.getDomNode === 'function')) { return; } const marginViewOverlays = editor.getDomNode()?.querySelector('.margin-view-overlays'); const handler = event => { const ev = event; if (ev.button !== 0) { return; } const target = ev.target; const firstElem = marginViewOverlays?.children[0]; const isFirstRow = target === firstElem || target.parentElement === firstElem; if (isFirstRow) { event.preventDefault(); event.stopPropagation(); } }; marginViewOverlays?.addEventListener('mousedown', handler); editor.onDidDispose(() => { marginViewOverlays?.removeEventListener('mousedown', handler); }); } const CssEditor = ({ value, onChange, syntaxRuleOptions, readOnly = false }) => { const theme = (0,_elementor_ui__WEBPACK_IMPORTED_MODULE_3__.useTheme)(); const containerRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); const editorRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); const monacoRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); const debounceTimer = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); const [hasContent, setHasContent] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(value.trim() !== ''); const [isValid, setIsValid] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(true); const [contentVersion, setContentVersion] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0); useOnUpdate(() => { const code = editorRef.current?.getModel()?.getValue() ?? ''; const userContent = (0,_visual_content_change_protection__WEBPACK_IMPORTED_MODULE_9__.getActual)(code); setHasContent(!userContent.trim()); onChange(userContent, isValid); }, [contentVersion, isValid]); const handleUserContentChange = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(newValue => { setHasContent(newValue.trim() !== ''); }, []); const handleResize = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => { editorRef.current?.layout(); }, []); const handleHeightChange = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(height => { if (containerRef.current) { containerRef.current.style.height = `${height}px`; } }, []); const handleEditorChange = () => { if (!editorRef.current || !monacoRef.current) { return; } (0,_css_validation__WEBPACK_IMPORTED_MODULE_7__.setCustomSyntaxRules)(editorRef?.current, monacoRef.current, syntaxRuleOptions); if (debounceTimer.current) { clearTimeout(debounceTimer.current); } debounceTimer.current = setTimeout(() => { setContentVersion(prev => prev + 1); }, 500); }; const handleEditorDidMount = createEditorDidMountHandler(editorRef, monacoRef, handleUserContentChange, setIsValid, syntaxRuleOptions); const handleReset = () => editorRef.current?.getModel()?.setValue((0,_visual_content_change_protection__WEBPACK_IMPORTED_MODULE_9__.setVisualContent)('')); (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { const timerRef = debounceTimer; return () => { const timer = timerRef.current; if (timer) { clearTimeout(timer); } }; }, []); return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_editor_ui__WEBPACK_IMPORTED_MODULE_2__.FloatingActionsBar, { actions: hasContent ? [/*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__.ClearIconButton, { key: "clear", tooltipText: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)('Clear', 'elementor-pro'), onClick: handleReset })] : [] }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__.Box, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_css_editor_styles__WEBPACK_IMPORTED_MODULE_6__.EditorWrapper, { ref: containerRef, dir: "ltr" }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_monaco_editor_react__WEBPACK_IMPORTED_MODULE_4__.Editor, { height: "100%", language: "css", theme: theme.palette.mode === 'dark' ? 'vs-dark' : 'vs', value: (0,_visual_content_change_protection__WEBPACK_IMPORTED_MODULE_9__.setVisualContent)(value), onMount: handleEditorDidMount, onChange: handleEditorChange, options: { lineNumbers: 'on', lineNumbersMinChars: 3, folding: true, minimap: { enabled: false }, fontFamily: 'Roboto, Arial, Helvetica, Verdana, sans-serif', fontSize: 12, renderLineHighlight: 'none', hideCursorInOverviewRuler: true, overviewRulerBorder: false, fixedOverflowWidgets: true, suggestFontSize: 10, suggestLineHeight: 14, stickyScroll: { enabled: false }, lineDecorationsWidth: 2, wordWrap: 'on', scrollBeyondLastLine: false, readOnly, editContext: false } }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_resize_handle__WEBPACK_IMPORTED_MODULE_8__.ResizeHandleComponent, { onResize: handleResize, containerRef: containerRef, onHeightChange: handleHeightChange })))); }; function useOnUpdate(callback, dependencies) { const hasMounted = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(false); (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { if (hasMounted.current) { callback(); } else { hasMounted.current = true; } // eslint-disable-next-line react-hooks/exhaustive-deps }, dependencies); } /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-validation.ts": /*!*********************************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-validation.ts ***! \*********************************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ clearMarkersFromVisualContent: function() { return /* binding */ clearMarkersFromVisualContent; }, /* harmony export */ setCustomSyntaxRules: function() { return /* binding */ setCustomSyntaxRules; }, /* harmony export */ validate: function() { return /* binding */ validate; } /* harmony export */ }); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n"); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__); const syntaxRules = { pseudoState: { pattern: '^\\s*[&]{0,1}\\s*(?::hover|:active|:focus)', regex: true, message: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('The use of pseudo-states is not permitted. Instead, switch to the desired pseudo state and add your custom code there.', 'elementor-pro') }, mediaQuery: { pattern: '@media\\s+[^{]*\\b(?:min-width|max-width|width)\\b', regex: true, message: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('The use of @media width queries is not permitted. Instead, switch to the desired breakpoint and add your custom code there.', 'elementor-pro') } }; function setCustomSyntaxRules(editor, monaco, options) { const model = editor.getModel(); if (!model) { return true; } const customMarkers = []; Object.entries(syntaxRules).forEach(([id, rule]) => { if (options?.rules?.[id] === false) { return; } const matches = model.findMatches(rule.pattern, true, rule.regex ?? false, true, null, true); matches.forEach(match => { customMarkers.push({ severity: monaco.MarkerSeverity.Error, message: rule.message, startLineNumber: match.range.startLineNumber, startColumn: match.range.startColumn, endLineNumber: match.range.endLineNumber, endColumn: match.range.endColumn, source: 'custom-css-rules' }); }); }); monaco.editor.setModelMarkers(model, 'custom-css-rules', customMarkers); return customMarkers.length === 0; } function validate(editor, monaco) { const model = editor.getModel(); if (!model) { return true; } const allMarkers = monaco.editor.getModelMarkers({ resource: model.uri }); return allMarkers.filter(marker => marker.severity === monaco.MarkerSeverity.Error).length === 0; } function clearMarkersFromVisualContent(editor, monaco) { const model = editor.getModel(); if (!model) { return; } const allMarkers = monaco.editor.getModelMarkers({ resource: model.uri }); const filteredMarkers = allMarkers.filter(marker => marker.startLineNumber !== 1); const nonCustomMarkers = filteredMarkers.filter(m => m.source !== 'custom-css-rules'); if (nonCustomMarkers.length === allMarkers.length) { return; } monaco.editor.setModelMarkers(model, 'css', nonCustomMarkers); } /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/resize-handle.tsx": /*!*********************************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/resize-handle.tsx ***! \*********************************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ResizeHandleComponent: function() { return /* binding */ ResizeHandleComponent; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _css_editor_styles__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./css-editor.styles */ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-editor.styles.ts"); const ResizeHandleComponent = ({ onResize, containerRef, onHeightChange }) => { const handleResizeMove = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(e => { const container = containerRef.current; if (!container) { return; } const containerRect = container.getBoundingClientRect(); const newHeight = Math.max(100, e.clientY - containerRect.top); onHeightChange?.(newHeight); onResize(newHeight); }, [containerRef, onResize, onHeightChange]); const handleResizeEnd = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(() => { document.removeEventListener('mousemove', handleResizeMove); document.removeEventListener('mouseup', handleResizeEnd); }, [handleResizeMove]); const handleResizeStart = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(e => { e.preventDefault(); e.stopPropagation(); document.addEventListener('mousemove', handleResizeMove); document.addEventListener('mouseup', handleResizeEnd); }, [handleResizeMove, handleResizeEnd]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => { return () => { document.removeEventListener('mousemove', handleResizeMove); document.removeEventListener('mouseup', handleResizeEnd); }; }, [handleResizeMove, handleResizeEnd]); return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_css_editor_styles__WEBPACK_IMPORTED_MODULE_1__.ResizeHandle, { onMouseDown: handleResizeStart, "aria-label": "Resize editor height", title: "Drag to resize editor height" }); }; /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/visual-content-change-protection.ts": /*!***************************************************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/visual-content-change-protection.ts ***! \***************************************************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getActual: function() { return /* binding */ getActual; }, /* harmony export */ preventChangeOnVisualContent: function() { return /* binding */ preventChangeOnVisualContent; }, /* harmony export */ setVisualContent: function() { return /* binding */ setVisualContent; } /* harmony export */ }); const preventChangeOnVisualContent = editor => { const model = editor.getModel(); if (!model) { return; } // On first load applyVisualContentStyling(editor, model); // On every change model.onDidChangeContent(() => { applyVisualContentStyling(editor, model); }); disableCursorOnVisualContent(editor); overridePushEditOperations(model); }; const applyVisualContentStyling = (editor, model) => { const decorationsCollection = editor.createDecorationsCollection(); const lineCount = model.getLineCount(); const decorations = []; decorations.push({ range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: model.getLineContent(1).length + 1 }, options: { inlineClassName: 'visual-content-dimmed', isWholeLine: false } }); if (lineCount > 1) { decorations.push({ range: { startLineNumber: lineCount, startColumn: 1, endLineNumber: lineCount, endColumn: model.getLineContent(lineCount).length + 1 }, options: { inlineClassName: 'visual-content-dimmed', isWholeLine: false } }); } decorationsCollection.set(decorations); }; const disableCursorOnVisualContent = editor => { const model = editor.getModel(); if (!model) { return; } editor.onDidChangeCursorPosition(e => { const totalLines = model.getLineCount(); const position = e.position; if (position.lineNumber === 1) { editor.setPosition({ lineNumber: 2, column: 1 }); } else if (position.lineNumber === totalLines) { editor.setPosition({ lineNumber: totalLines - 1, column: model.getLineContent(totalLines - 1).length + 1 }); } }); }; const overridePushEditOperations = model => { const originalPushEditOperations = model.pushEditOperations; model.pushEditOperations = (beforeCursorState, editOperations, cursorStateComputer) => { const totalLines = model.getLineCount(); const modelRange = model.getFullModelRange(); const filteredOperations = editOperations.filter(operation => { const range = operation.range; const affectsProtectedLine = range.startLineNumber === 1 || range.endLineNumber === 1 || range.startLineNumber === totalLines || range.endLineNumber === totalLines; if (affectsProtectedLine && isFullContentReplacement(range, modelRange) && hasVisualContent(operation.text)) { return true; } return !affectsProtectedLine; }); return originalPushEditOperations.call(model, beforeCursorState, filteredOperations, cursorStateComputer); }; }; const isFullContentReplacement = (range, modelRange) => { return range.startLineNumber === modelRange.startLineNumber && range.endLineNumber === modelRange.endLineNumber && range.startColumn === modelRange.startColumn && range.endColumn === modelRange.endColumn; }; const hasVisualContent = text => { if (!text) { return false; } return text.startsWith('element.style {') && text.endsWith('}'); }; const setVisualContent = value => { const trimmed = value.trim(); return `element.style {\n${trimmed ? ' ' + trimmed.replace(/\n/g, '\n ') + '\n' : ' \n'}}`; }; const getActual = value => { const lines = value.split('\n'); if (lines.length < 2) { return ''; } return lines.slice(1, -1).map(line => line.replace(/^ {2}/, '')).join('\n'); }; /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/controls/attributes-control.tsx": /*!********************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/controls/attributes-control.tsx ***! \********************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AttributesControl: function() { return /* binding */ AttributesControl; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @elementor/editor-controls */ "@elementor/editor-controls"); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n"); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__); const AttributesControl = (0,_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__.createControl)(() => { const getHelperText = (key, value) => { if (value && !key) { return { keyHelper: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__.__)("Empty attribute names aren't valid and won't render on the page.", 'elementor-pro') }; } return {}; }; return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__.KeyValueControl, { keyName: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__.__)('Name', 'elementor-pro'), valueName: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__.__)('Value', 'elementor-pro'), regexKey: "^[a-zA-Z0-9_-]*$", validationErrorMessage: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__.__)('Names can only use letters, numbers, dashes (-) and underscores (_).', 'elementor-pro'), getHelperText: getHelperText }); }); /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/controls/display-conditions-control.tsx": /*!****************************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/controls/display-conditions-control.tsx ***! \****************************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DisplayConditionsControl: function() { return /* binding */ DisplayConditionsControl; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @elementor/editor-controls */ "@elementor/editor-controls"); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _elementor_icons__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @elementor/icons */ "@elementor/icons"); /* harmony import */ var _elementor_icons__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_elementor_icons__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _elementor_ui__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @elementor/ui */ "@elementor/ui"); /* harmony import */ var _elementor_ui__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n"); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_i18n__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var _prop_types_display_conditions__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../prop-types/display-conditions */ "./packages/packages/pro/editor-controls-extended/src/prop-types/display-conditions.ts"); /* harmony import */ var _utils_display_conditions_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils/display-conditions-utils */ "./packages/packages/pro/editor-controls-extended/src/utils/display-conditions-utils.ts"); const OPEN_MODAL_EVENT = 'elementor/display-conditions/open'; const CLOSE_MODAL_EVENT = 'elementor/display-conditions/close'; const SET_CACHE_NOTICE_STATUS_EVENT = 'elementor/display-conditions/set-cache-notice-status'; const ariaLabel = (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_4__.__)('Display Conditions', 'elementor-pro'); async function setCacheNoticeStatus() { return new Promise((resolve, reject) => { window.dispatchEvent(new CustomEvent(SET_CACHE_NOTICE_STATUS_EVENT, { detail: { resolve, reject } })); }); } const DisplayConditionsControl = (0,_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__.createControl)(({ disabled = false }) => { const { setValue, value: displayConditionsValue } = (0,_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__.useBoundProp)(_prop_types_display_conditions__WEBPACK_IMPORTED_MODULE_5__.displayConditionsPropTypeUtil); const [isModalOpen, setIsModalOpen] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false); const hasValue = !!displayConditionsValue?.length; const setControlValue = value => setValue((0,_utils_display_conditions_utils__WEBPACK_IMPORTED_MODULE_6__.transformV3ToV4)(JSON.parse(value ?? '[]'))); const getControlValue = () => (0,_utils_display_conditions_utils__WEBPACK_IMPORTED_MODULE_6__.transformV4ToV3)(displayConditionsValue) ?? []; const onClose = () => { setIsModalOpen(false); window.dispatchEvent(new CustomEvent(CLOSE_MODAL_EVENT)); }; const conditions = getControlValue(); const openConditionsModal = () => { setIsModalOpen(true); window.dispatchEvent(new CustomEvent(OPEN_MODAL_EVENT, { detail: { props: { getControlValue, setControlValue, onClose, setCacheNoticeStatus } } })); }; return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__.Stack, { direction: "row", spacing: 2, sx: { justifyContent: 'flex-end', alignItems: 'center' } }, disabled && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__.Chip, { icon: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_icons__WEBPACK_IMPORTED_MODULE_2__.CrownFilledIcon, { fontSize: "tiny" }), size: "tiny", color: "promotion", variant: "standard", sx: { width: '20px', '& .MuiChip-label': { display: 'none' } } }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__.Tooltip, { title: ariaLabel, placement: "top" }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__.Box, { sx: { cursor: disabled ? 'not-allowed' : 'pointer', display: 'inline-flex' } }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_ui__WEBPACK_IMPORTED_MODULE_3__.ToggleButton, { value: JSON.stringify(conditions), size: "tiny", variant: "outline", "aria-pressed": hasValue, "aria-expanded": isModalOpen, selected: hasValue, "aria-haspopup": "dialog", "aria-label": ariaLabel, onClick: openConditionsModal, disabled: disabled, sx: { pointerEvents: disabled ? 'none' : 'auto' }, "data-behavior": "display-conditions" }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_icons__WEBPACK_IMPORTED_MODULE_2__.SitemapIcon, { fontSize: "tiny" })))))); }); /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/controls/options-control.tsx": /*!*****************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/controls/options-control.tsx ***! \*****************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ OptionsControl: function() { return /* binding */ OptionsControl; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @elementor/editor-controls */ "@elementor/editor-controls"); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n"); /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__); const OptionsControl = (0,_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__.createControl)(() => { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_1__.KeyValueControl, { keyName: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__.__)('Name', 'elementor-pro'), valueName: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__.__)('Value', 'elementor-pro') }); }); /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/extend-transition-properties.ts": /*!********************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/extend-transition-properties.ts ***! \********************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ extendTransitionProperties: function() { return /* binding */ extendTransitionProperties; }, /* harmony export */ transitionProperties: function() { return /* reexport safe */ _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionProperties; }, /* harmony export */ transitionsItemsList: function() { return /* reexport safe */ _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionsItemsList; } /* harmony export */ }); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/editor-controls */ "@elementor/editor-controls"); /* harmony import */ var _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__); function extendTransitionProperties(isDisabled = false) { if (!_elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionProperties || _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionProperties.length === 0) { return; } _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionProperties.forEach(category => { category.properties.forEach(property => { if (property.value !== 'all') { property.isDisabled = isDisabled; } }); }); _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionsItemsList.splice(0, _elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionsItemsList.length, ..._elementor_editor_controls__WEBPACK_IMPORTED_MODULE_0__.transitionProperties.map(category => ({ label: category.label, items: category.properties.map(property => property.label) }))); } /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/init.ts": /*!********************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/init.ts ***! \********************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ init: function() { return /* binding */ init; } /* harmony export */ }); /* harmony import */ var _elementor_license_api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/license-api */ "@elementor/license-api"); /* harmony import */ var _elementor_license_api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_license_api__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _extend_transition_properties__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./extend-transition-properties */ "./packages/packages/pro/editor-controls-extended/src/extend-transition-properties.ts"); async function init() { const [isExpired, features] = await Promise.all([(0,_elementor_license_api__WEBPACK_IMPORTED_MODULE_0__.fetchLicenseStatus)().catch(() => false), (0,_elementor_license_api__WEBPACK_IMPORTED_MODULE_0__.fetchTierFeatures)().catch(() => [])]); if (features.includes('transitions')) { (0,_extend_transition_properties__WEBPACK_IMPORTED_MODULE_1__.extendTransitionProperties)(isExpired); } } /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/prop-types/condition-group.ts": /*!******************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/prop-types/condition-group.ts ***! \******************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ conditionGroupPropTypeUtil: function() { return /* binding */ conditionGroupPropTypeUtil; } /* harmony export */ }); /* harmony import */ var _elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/editor-props */ "@elementor/editor-props"); /* harmony import */ var _elementor_editor_props__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _elementor_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @elementor/schema */ "@elementor/schema"); /* harmony import */ var _elementor_schema__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_elementor_schema__WEBPACK_IMPORTED_MODULE_1__); const unknownChildrenSchema = _elementor_schema__WEBPACK_IMPORTED_MODULE_1__.z.any().nullable(); const conditionGroupPropTypeUtil = (0,_elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__.createPropUtils)('condition-group', _elementor_schema__WEBPACK_IMPORTED_MODULE_1__.z.array(unknownChildrenSchema)); /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/prop-types/display-conditions.ts": /*!*********************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/prop-types/display-conditions.ts ***! \*********************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ displayConditionsPropTypeUtil: function() { return /* binding */ displayConditionsPropTypeUtil; } /* harmony export */ }); /* harmony import */ var _elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/editor-props */ "@elementor/editor-props"); /* harmony import */ var _elementor_editor_props__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _elementor_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @elementor/schema */ "@elementor/schema"); /* harmony import */ var _elementor_schema__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_elementor_schema__WEBPACK_IMPORTED_MODULE_1__); const unknownChildrenSchema = _elementor_schema__WEBPACK_IMPORTED_MODULE_1__.z.any().nullable(); const displayConditionsPropTypeUtil = (0,_elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__.createPropUtils)('display-conditions', _elementor_schema__WEBPACK_IMPORTED_MODULE_1__.z.array(unknownChildrenSchema)); /***/ }), /***/ "./packages/packages/pro/editor-controls-extended/src/utils/display-conditions-utils.ts": /*!**********************************************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/utils/display-conditions-utils.ts ***! \**********************************************************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ transformV3ToV4: function() { return /* binding */ transformV3ToV4; }, /* harmony export */ transformV4ToV3: function() { return /* binding */ transformV4ToV3; } /* harmony export */ }); /* harmony import */ var _elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/editor-props */ "@elementor/editor-props"); /* harmony import */ var _elementor_editor_props__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__); // Value must be falsy for navigator indication to work properly function transformV3ToV4(displayConditions) { if (!Array.isArray(displayConditions) || !displayConditions?.length) { return null; } const transformed = displayConditions.filter(conditionGroup => !!conditionGroup?.length).map(conditionGroup => ({ $$type: 'condition-group', value: conditionGroup.map(condition => _elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__.stringPropTypeUtil.create(JSON.stringify(condition))) })); return transformed.length ? transformed : null; } function transformV4ToV3(value) { const conditionGroups = value; const transformed = conditionGroups?.map(group => group.value.map(conditions => { return JSON.parse(_elementor_editor_props__WEBPACK_IMPORTED_MODULE_0__.stringPropTypeUtil.extract(conditions) ?? '[]'); })) ?? null; return getStructuredConditions(transformed); } function shouldConvertConditionsStructure(conditions) { return !!conditions?.length && !Array.isArray(conditions?.[0]); } function getStructuredConditions(conditions) { return shouldConvertConditionsStructure(conditions) ? [conditions] : conditions; } /***/ }), /***/ "./node_modules/state-local/lib/es/state-local.js": /*!********************************************************!*\ !*** ./node_modules/state-local/lib/es/state-local.js ***! \********************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function compose() { for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { fns[_key] = arguments[_key]; } return function (x) { return fns.reduceRight(function (y, f) { return f(y); }, x); }; } function curry(fn) { return function curried() { var _this = this; for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return args.length >= fn.length ? fn.apply(this, args) : function () { for (var _len3 = arguments.length, nextArgs = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { nextArgs[_key3] = arguments[_key3]; } return curried.apply(_this, [].concat(args, nextArgs)); }; }; } function isObject(value) { return {}.toString.call(value).includes('Object'); } function isEmpty(obj) { return !Object.keys(obj).length; } function isFunction(value) { return typeof value === 'function'; } function hasOwnProperty(object, property) { return Object.prototype.hasOwnProperty.call(object, property); } function validateChanges(initial, changes) { if (!isObject(changes)) errorHandler('changeType'); if (Object.keys(changes).some(function (field) { return !hasOwnProperty(initial, field); })) errorHandler('changeField'); return changes; } function validateSelector(selector) { if (!isFunction(selector)) errorHandler('selectorType'); } function validateHandler(handler) { if (!(isFunction(handler) || isObject(handler))) errorHandler('handlerType'); if (isObject(handler) && Object.values(handler).some(function (_handler) { return !isFunction(_handler); })) errorHandler('handlersType'); } function validateInitial(initial) { if (!initial) errorHandler('initialIsRequired'); if (!isObject(initial)) errorHandler('initialType'); if (isEmpty(initial)) errorHandler('initialContent'); } function throwError(errorMessages, type) { throw new Error(errorMessages[type] || errorMessages["default"]); } var errorMessages = { initialIsRequired: 'initial state is required', initialType: 'initial state should be an object', initialContent: 'initial state shouldn\'t be an empty object', handlerType: 'handler should be an object or a function', handlersType: 'all handlers should be a functions', selectorType: 'selector should be a function', changeType: 'provided value of changes should be an object', changeField: 'it seams you want to change a field in the state which is not specified in the "initial" state', "default": 'an unknown error accured in `state-local` package' }; var errorHandler = curry(throwError)(errorMessages); var validators = { changes: validateChanges, selector: validateSelector, handler: validateHandler, initial: validateInitial }; function create(initial) { var handler = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; validators.initial(initial); validators.handler(handler); var state = { current: initial }; var didUpdate = curry(didStateUpdate)(state, handler); var update = curry(updateState)(state); var validate = curry(validators.changes)(initial); var getChanges = curry(extractChanges)(state); function getState() { var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function (state) { return state; }; validators.selector(selector); return selector(state.current); } function setState(causedChanges) { compose(didUpdate, update, validate, getChanges)(causedChanges); } return [getState, setState]; } function extractChanges(state, causedChanges) { return isFunction(causedChanges) ? causedChanges(state.current) : causedChanges; } function updateState(state, changes) { state.current = _objectSpread2(_objectSpread2({}, state.current), changes); return changes; } function didStateUpdate(state, handler, changes) { isFunction(handler) ? handler(state.current) : Object.keys(changes).forEach(function (field) { var _handler$field; return (_handler$field = handler[field]) === null || _handler$field === void 0 ? void 0 : _handler$field.call(handler, state.current[field]); }); return changes; } var index = { create: create }; /* harmony default export */ __webpack_exports__["default"] = (index); /***/ }), /***/ "react": /*!**************************!*\ !*** external ["React"] ***! \**************************/ /***/ (function(module) { module.exports = window["React"]; /***/ }), /***/ "@elementor/editor-controls": /*!*************************************************!*\ !*** external ["elementorV2","editorControls"] ***! \*************************************************/ /***/ (function(module) { module.exports = window["elementorV2"]["editorControls"]; /***/ }), /***/ "@elementor/editor-props": /*!**********************************************!*\ !*** external ["elementorV2","editorProps"] ***! \**********************************************/ /***/ (function(module) { module.exports = window["elementorV2"]["editorProps"]; /***/ }), /***/ "@elementor/editor-ui": /*!*******************************************!*\ !*** external ["elementorV2","editorUi"] ***! \*******************************************/ /***/ (function(module) { module.exports = window["elementorV2"]["editorUi"]; /***/ }), /***/ "@elementor/icons": /*!****************************************!*\ !*** external ["elementorV2","icons"] ***! \****************************************/ /***/ (function(module) { module.exports = window["elementorV2"]["icons"]; /***/ }), /***/ "@elementor/license-api": /*!*********************************************!*\ !*** external ["elementorV2","licenseApi"] ***! \*********************************************/ /***/ (function(module) { module.exports = window["elementorV2"]["licenseApi"]; /***/ }), /***/ "@elementor/schema": /*!*****************************************!*\ !*** external ["elementorV2","schema"] ***! \*****************************************/ /***/ (function(module) { module.exports = window["elementorV2"]["schema"]; /***/ }), /***/ "@elementor/ui": /*!*************************************!*\ !*** external ["elementorV2","ui"] ***! \*************************************/ /***/ (function(module) { module.exports = window["elementorV2"]["ui"]; /***/ }), /***/ "@wordpress/i18n": /*!******************************!*\ !*** external ["wp","i18n"] ***! \******************************/ /***/ (function(module) { module.exports = window["wp"]["i18n"]; /***/ }), /***/ "./node_modules/@monaco-editor/react/dist/index.mjs": /*!**********************************************************!*\ !*** ./node_modules/@monaco-editor/react/dist/index.mjs ***! \**********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DiffEditor: function() { return /* binding */ we; }, /* harmony export */ Editor: function() { return /* binding */ de; }, /* harmony export */ "default": function() { return /* binding */ Ft; }, /* harmony export */ loader: function() { return /* reexport safe */ _monaco_editor_loader__WEBPACK_IMPORTED_MODULE_0__["default"]; }, /* harmony export */ useMonaco: function() { return /* binding */ Le; } /* harmony export */ }); /* harmony import */ var _monaco_editor_loader__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @monaco-editor/loader */ "./node_modules/@monaco-editor/loader/lib/es/index.js"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "react"); var le={wrapper:{display:"flex",position:"relative",textAlign:"initial"},fullWidth:{width:"100%"},hide:{display:"none"}},v=le;var ae={container:{display:"flex",height:"100%",width:"100%",justifyContent:"center",alignItems:"center"}},Y=ae;function Me({children:e}){return react__WEBPACK_IMPORTED_MODULE_1__.createElement("div",{style:Y.container},e)}var Z=Me;var $=Z;function Ee({width:e,height:r,isEditorReady:n,loading:t,_ref:a,className:m,wrapperProps:E}){return react__WEBPACK_IMPORTED_MODULE_1__.createElement("section",{style:{...v.wrapper,width:e,height:r},...E},!n&&react__WEBPACK_IMPORTED_MODULE_1__.createElement($,null,t),react__WEBPACK_IMPORTED_MODULE_1__.createElement("div",{ref:a,style:{...v.fullWidth,...!n&&v.hide},className:m}))}var ee=Ee;var H=(0,react__WEBPACK_IMPORTED_MODULE_1__.memo)(ee);function Ce(e){(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(e,[])}var k=Ce;function he(e,r,n=!0){let t=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(!0);(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(t.current||!n?()=>{t.current=!1}:e,r)}var l=he;function D(){}function h(e,r,n,t){return De(e,t)||be(e,r,n,t)}function De(e,r){return e.editor.getModel(te(e,r))}function be(e,r,n,t){return e.editor.createModel(r,n,t?te(e,t):void 0)}function te(e,r){return e.Uri.parse(r)}function Oe({original:e,modified:r,language:n,originalLanguage:t,modifiedLanguage:a,originalModelPath:m,modifiedModelPath:E,keepCurrentOriginalModel:g=!1,keepCurrentModifiedModel:N=!1,theme:x="light",loading:P="Loading...",options:y={},height:V="100%",width:z="100%",className:F,wrapperProps:j={},beforeMount:A=D,onMount:q=D}){let[M,O]=(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(!1),[T,s]=(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(!0),u=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null),c=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null),w=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null),d=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(q),o=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(A),b=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(!1);k(()=>{let i=_monaco_editor_loader__WEBPACK_IMPORTED_MODULE_0__["default"].init();return i.then(f=>(c.current=f)&&s(!1)).catch(f=>f?.type!=="cancelation"&&console.error("Monaco initialization: error:",f)),()=>u.current?I():i.cancel()}),l(()=>{if(u.current&&c.current){let i=u.current.getOriginalEditor(),f=h(c.current,e||"",t||n||"text",m||"");f!==i.getModel()&&i.setModel(f)}},[m],M),l(()=>{if(u.current&&c.current){let i=u.current.getModifiedEditor(),f=h(c.current,r||"",a||n||"text",E||"");f!==i.getModel()&&i.setModel(f)}},[E],M),l(()=>{let i=u.current.getModifiedEditor();i.getOption(c.current.editor.EditorOption.readOnly)?i.setValue(r||""):r!==i.getValue()&&(i.executeEdits("",[{range:i.getModel().getFullModelRange(),text:r||"",forceMoveMarkers:!0}]),i.pushUndoStop())},[r],M),l(()=>{u.current?.getModel()?.original.setValue(e||"")},[e],M),l(()=>{let{original:i,modified:f}=u.current.getModel();c.current.editor.setModelLanguage(i,t||n||"text"),c.current.editor.setModelLanguage(f,a||n||"text")},[n,t,a],M),l(()=>{c.current?.editor.setTheme(x)},[x],M),l(()=>{u.current?.updateOptions(y)},[y],M);let L=(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)(()=>{if(!c.current)return;o.current(c.current);let i=h(c.current,e||"",t||n||"text",m||""),f=h(c.current,r||"",a||n||"text",E||"");u.current?.setModel({original:i,modified:f})},[n,r,a,e,t,m,E]),U=(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)(()=>{!b.current&&w.current&&(u.current=c.current.editor.createDiffEditor(w.current,{automaticLayout:!0,...y}),L(),c.current?.editor.setTheme(x),O(!0),b.current=!0)},[y,x,L]);(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{M&&d.current(u.current,c.current)},[M]),(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{!T&&!M&&U()},[T,M,U]);function I(){let i=u.current?.getModel();g||i?.original?.dispose(),N||i?.modified?.dispose(),u.current?.dispose()}return react__WEBPACK_IMPORTED_MODULE_1__.createElement(H,{width:z,height:V,isEditorReady:M,loading:P,_ref:w,className:F,wrapperProps:j})}var ie=Oe;var we=(0,react__WEBPACK_IMPORTED_MODULE_1__.memo)(ie);function Pe(){let[e,r]=(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(_monaco_editor_loader__WEBPACK_IMPORTED_MODULE_0__["default"].__getMonacoInstance());return k(()=>{let n;return e||(n=_monaco_editor_loader__WEBPACK_IMPORTED_MODULE_0__["default"].init(),n.then(t=>{r(t)})),()=>n?.cancel()}),e}var Le=Pe;function He(e){let r=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)();return (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{r.current=e},[e]),r.current}var se=He;var _=new Map;function Ve({defaultValue:e,defaultLanguage:r,defaultPath:n,value:t,language:a,path:m,theme:E="light",line:g,loading:N="Loading...",options:x={},overrideServices:P={},saveViewState:y=!0,keepCurrentModel:V=!1,width:z="100%",height:F="100%",className:j,wrapperProps:A={},beforeMount:q=D,onMount:M=D,onChange:O,onValidate:T=D}){let[s,u]=(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(!1),[c,w]=(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(!0),d=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null),o=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null),b=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null),L=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(M),U=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(q),I=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(),i=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(t),f=se(m),Q=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(!1),B=(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(!1);k(()=>{let p=_monaco_editor_loader__WEBPACK_IMPORTED_MODULE_0__["default"].init();return p.then(R=>(d.current=R)&&w(!1)).catch(R=>R?.type!=="cancelation"&&console.error("Monaco initialization: error:",R)),()=>o.current?pe():p.cancel()}),l(()=>{let p=h(d.current,e||t||"",r||a||"",m||n||"");p!==o.current?.getModel()&&(y&&_.set(f,o.current?.saveViewState()),o.current?.setModel(p),y&&o.current?.restoreViewState(_.get(m)))},[m],s),l(()=>{o.current?.updateOptions(x)},[x],s),l(()=>{!o.current||t===void 0||(o.current.getOption(d.current.editor.EditorOption.readOnly)?o.current.setValue(t):t!==o.current.getValue()&&(B.current=!0,o.current.executeEdits("",[{range:o.current.getModel().getFullModelRange(),text:t,forceMoveMarkers:!0}]),o.current.pushUndoStop(),B.current=!1))},[t],s),l(()=>{let p=o.current?.getModel();p&&a&&d.current?.editor.setModelLanguage(p,a)},[a],s),l(()=>{g!==void 0&&o.current?.revealLine(g)},[g],s),l(()=>{d.current?.editor.setTheme(E)},[E],s);let X=(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)(()=>{if(!(!b.current||!d.current)&&!Q.current){U.current(d.current);let p=m||n,R=h(d.current,t||e||"",r||a||"",p||"");o.current=d.current?.editor.create(b.current,{model:R,automaticLayout:!0,...x},P),y&&o.current.restoreViewState(_.get(p)),d.current.editor.setTheme(E),g!==void 0&&o.current.revealLine(g),u(!0),Q.current=!0}},[e,r,n,t,a,m,x,P,y,E,g]);(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{s&&L.current(o.current,d.current)},[s]),(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{!c&&!s&&X()},[c,s,X]),i.current=t,(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{s&&O&&(I.current?.dispose(),I.current=o.current?.onDidChangeModelContent(p=>{B.current||O(o.current.getValue(),p)}))},[s,O]),(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{if(s){let p=d.current.editor.onDidChangeMarkers(R=>{let G=o.current.getModel()?.uri;if(G&&R.find(J=>J.path===G.path)){let J=d.current.editor.getModelMarkers({resource:G});T?.(J)}});return()=>{p?.dispose()}}return()=>{}},[s,T]);function pe(){I.current?.dispose(),V?y&&_.set(m,o.current.saveViewState()):o.current.getModel()?.dispose(),o.current.dispose()}return react__WEBPACK_IMPORTED_MODULE_1__.createElement(H,{width:z,height:F,isEditorReady:s,loading:N,_ref:b,className:j,wrapperProps:A})}var fe=Ve;var de=(0,react__WEBPACK_IMPORTED_MODULE_1__.memo)(fe);var Ft=de; //# sourceMappingURL=index.mjs.map /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ if (!(moduleId in __webpack_modules__)) { /******/ delete __webpack_module_cache__[moduleId]; /******/ var e = new Error("Cannot find module '" + moduleId + "'"); /******/ e.code = 'MODULE_NOT_FOUND'; /******/ throw e; /******/ } /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ !function() { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function() { return module['default']; } : /******/ function() { return module; }; /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ !function() { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = function(exports, definition) { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ !function() { /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } /******/ }(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ !function() { /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ }(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk. !function() { /*!*********************************************************************!*\ !*** ./packages/packages/pro/editor-controls-extended/src/index.ts ***! \*********************************************************************/ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AttributesControl: function() { return /* reexport safe */ _controls_attributes_control__WEBPACK_IMPORTED_MODULE_1__.AttributesControl; }, /* harmony export */ CssEditor: function() { return /* reexport safe */ _components_css_code_editor_css_editor__WEBPACK_IMPORTED_MODULE_6__.CssEditor; }, /* harmony export */ DisplayConditionsControl: function() { return /* reexport safe */ _controls_display_conditions_control__WEBPACK_IMPORTED_MODULE_3__.DisplayConditionsControl; }, /* harmony export */ OptionsControl: function() { return /* reexport safe */ _controls_options_control__WEBPACK_IMPORTED_MODULE_2__.OptionsControl; }, /* harmony export */ conditionGroupPropTypeUtil: function() { return /* reexport safe */ _prop_types_condition_group__WEBPACK_IMPORTED_MODULE_5__.conditionGroupPropTypeUtil; }, /* harmony export */ displayConditionsPropTypeUtil: function() { return /* reexport safe */ _prop_types_display_conditions__WEBPACK_IMPORTED_MODULE_4__.displayConditionsPropTypeUtil; } /* harmony export */ }); /* harmony import */ var _init__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./init */ "./packages/packages/pro/editor-controls-extended/src/init.ts"); /* harmony import */ var _controls_attributes_control__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/attributes-control */ "./packages/packages/pro/editor-controls-extended/src/controls/attributes-control.tsx"); /* harmony import */ var _controls_options_control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/options-control */ "./packages/packages/pro/editor-controls-extended/src/controls/options-control.tsx"); /* harmony import */ var _controls_display_conditions_control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./controls/display-conditions-control */ "./packages/packages/pro/editor-controls-extended/src/controls/display-conditions-control.tsx"); /* harmony import */ var _prop_types_display_conditions__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./prop-types/display-conditions */ "./packages/packages/pro/editor-controls-extended/src/prop-types/display-conditions.ts"); /* harmony import */ var _prop_types_condition_group__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./prop-types/condition-group */ "./packages/packages/pro/editor-controls-extended/src/prop-types/condition-group.ts"); /* harmony import */ var _components_css_code_editor_css_editor__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/css-code-editor/css-editor */ "./packages/packages/pro/editor-controls-extended/src/components/css-code-editor/css-editor.tsx"); (0,_init__WEBPACK_IMPORTED_MODULE_0__.init)(); }(); (window.elementorV2 = window.elementorV2 || {}).editorControlsExtended = __webpack_exports__; /******/ })() ; window.elementorV2.editorControlsExtended?.init?.(); Everything You Need to Know About Travel in Vietnam | Char's Footsteps https://www.charsfootsteps.com/travel/asia/vietnam/ Best Female Travel Blogs 2024 Tue, 08 Jul 2025 18:36:08 +0000 en-US hourly 1 Exploring Hanoi: A Full Guide on the Best Things to Do https://www.charsfootsteps.com/travel/asia/vietnam/exploring-hanoi-the-best-things-to-do/?utm_source=rss&utm_medium=rss&utm_campaign=exploring-hanoi-the-best-things-to-do https://www.charsfootsteps.com/travel/asia/vietnam/exploring-hanoi-the-best-things-to-do/#respond Thu, 15 Feb 2024 06:44:58 +0000 https://www.charsfootsteps.com/?p=2712 Hanoi, the capital of Vietnam, is a city where ancient traditions coexist with modern developments. Nestled along the banks of the Red River, Hanoi offers a glimpse into the nation’s history, culture, and daily life. With good access to international airports, Hanoi is often a starting point of a trip. Two common ways to travel […]

The post Exploring Hanoi: A Full Guide on the Best Things to Do appeared first on Char's Footsteps.

]]>
Hanoi, the capital of Vietnam, is a city where ancient traditions coexist with modern developments. Nestled along the banks of the Red River, Hanoi offers a glimpse into the nation’s history, culture, and daily life. With good access to international airports, Hanoi is often a starting point of a trip. Two common ways to travel Vietnam are either North to South (or vice versa) or by region; North, Central or South. So if you to explore the North of Vietnam, or doing a big south-north trip, you’re likely to pay Hanoi a visit. Here is a guide of best things to do in Hanoi and some travel tips from my visit.

Getting To Hanoi

Hanoi’s Noi Bai International Airport, located approximately 30km north of the city centre, offers a range of domestic and international flights. Taxis and airport shuttles provide convenient transportation options to the city, typically taking around 30 to 45 minutes depending on traffic. However, if you’re on a tight budget (like I was), it’s possible to get to the city via public transport.

For those exploring Vietnam by train, Hanoi is a major railway hub. The Hanoi Railway Station is centrally located and easy to access. The train rides around here offer amazing views of Vietnam’s countryside and it was my favourite way to travel through Vietnam.

If you’d rather go by road, there are a number of budget-friendly bus options. Most cities and towns I visited had tour shops of some capacity, where you could learn about different bus routes and sort tickets. These shops are in abundance in the Old Quarter and was how I sorted bus tickets for my Hanoi to Tam Coc trip.

How Long to Stay in Hanoi

How long you stay in Hanoi will largely depend on your budget, time in Vietnam and what you’re interested in seeing. Hanoi is typically used as a base, to explore, but to do day trips from. I’d recommend spending at least 3 days in Hanoi to properly enjoy what the city has to offer. But longer if you intend to do day trips from the city, e.g. to Tam Coc. I stayed in Hanoi for a week and felt it was enough time to explore the area without rushing.

Best Things to Do in Hanoi

There’s so much to see and do in Hanoi! I was lucky to spend a week there, so here are the best things I did during my time there.

Hanoi’s Old Quarter

The Old Quarter was my favourite place to explore in Hanoi and where based myself in the city. The Old Quarter, known as “36 Pho Phuong” or the 36 Streets, is a labyrinth of narrow streets and alleys dating back to the 13th century. Each street was originally associated with a specific trade, and while the city has expanded considerably, the area remains a bustling hub of activity. The best way to enjoy the Old Quarter is to stroll through the maze-like streets and witness the eclectic mix of shops, markets, and street vendors. It’s a great way to see the fun street life and discover local gems tucked away in the historic alleys.

Hanoi Train Street

If you’ve done image searches of Hanoi, it’s likely you would have stumbled across photos of the famous Train Street. Tucked away in Hanoi’s Old Quarter, Train Street features homes, cafes and restaurants located mere feet away from active railway tracks.

Consider visiting one of the cafes here for a ground-shaking experience as trains race by you! You can also find some refreshment and souvenir stalls along the street too. I enjoyed visiting the street, but found it to be very touristy. I didn’t end up staying in a cafe in the end.

Authorities have regularly tried to shut the street down from tourists over the growing safety concerns.

Ho Chi Minh Mausoleum and Complex

A visit to the Ho Chi Minh Mausoleum and its surrounding complex provides a fascinating insight into the life of Ho Chi Minh. The mausoleum houses his embalmed body and is a symbol of deep reverence for the country’s founding father. The nearby Presidential Palace, One Pillar Pagoda, and Ho Chi Minh’s Stilt House are also integral parts of the complex, offering a comprehensive view of Vietnam’s political and cultural history.

The museum is free, but note, there are strict policies you must obey to visit. In terms of the dress policy, you must cover shoulders and knees. You’ll be checked at arrival so be sure to dress respectfully. You must also leave your bags at the entrance – I didn’t have one but I believe there were safe areas for belongings. The strictest policies include no photos within the Mausoleum and no talking and no finger-pointing. The Ho Chi Minh Mausoleum is only open between 8-11am and is closed on Mondays and Fridays. Be sure to check opening hours when you’re there to save a failed attempt to visit (like I had).

Temple of Literature (Van Mieu-Quoc Tu Giam)

The Temple of Literature, Vietnam’s first national university, is a serene complex dedicated to Confucius and scholars. This 11th-century temple is home to five peaceful courtyards, with traditional pavilions and red-tiled roofs. There are a number of stunning gardens with statues and fountains to explore, along with the iconic “Well of Heavenly Clarity.” The site reflects Vietnam’s commitment to education and stands as a symbol of intellectual achievement. The Temple of Literature is a great place to take refuge from the city’s craziness and enjoy some calm. An adult ticket costs 30,000 VND so it’s worth popping in for a few hours and having an explore.

Hoan Kiem Lake and Ngoc Son Temple

Hoan Kiem Lake, located in the heart of Hanoi, is a scenic oasis surrounded by parks and historic landmarks. The lake and its surroundings are a great place to take a leisurely walk or to sit and people watch. In Hoan Kiem Lake, you’ll find the iconic red bridge leading to Ngoc Son Temple on a small island. I would get up early to avoid the heat and enjoy lake walks with a fresh fruit juice. So peaceful! The temple, dedicated to war hero Tran Hung Dao, offers a glimpse into Vietnam’s spiritual traditions. This area seems to be a popular spot for locals engaging in recreational activities too, so it got lively at times. There were lots of good cafes and brunch style spots in the surrounding areas too.

Hỏa Lò Prison (Maison Centrale)

Hỏa Lò Prison, once known as the “Hanoi Hilton,” serves as a stark reminder of Vietnam’s tumultuous history. Originally built by the French colonialists to house political prisoners, the prison later became infamous for housing American prisoners of war during the Vietnam War. The museum offers a somber look at conditions faced by inmates and provides historical context for the complex relationships between Vietnam and foreign powers. Entry to Hỏa Lò Prison cost 30.000 VND (£1!!) and you can find out more about it here.

The Spas!

Hanoi is home to a number of spas, offering a wide range of treatments for very reasonable prices. After a few days of sightseeing, and eating everything in sight, I opted for a spa afternoon. Enjoying a 90 minute massage and 30 minute mini facial was exactly what I needed. Particularly after lugging a huge backpack around for a month. There are so many to choose from, I’d recommend searching for ones near your accommodation or wandering through the Old Quarter and seeing what takes your fancy.

Vietnam Museum of Ethnology

To get an even deeper understanding of Vietnam’s diverse ethnic groups, check out the Vietnam Museum of Ethnology. The museum is home to artefacts, traditional clothing, and exhibits detailing the customs and lifestyles of the country’s 54 ethnic minorities. It provides a comprehensive overview of Vietnam’s culture and pays tribute to the nation’s rich ethnic diversity. Entry fees for the Museum of Ethnology are 40,000 VND and you can read more about what’s on offer here. For those visiting Vietnam in rainy season, I found visiting museums were a great way to enjoy the city during a downpour!

Best Food in Hanoi

Hanoi’s culinary scene is renowned for its diverse street food and traditional dishes. I spent most of my time in Hanoi Old Quarter, so sampled a lot of street food there and probably more ‘touristy’ type restaurants. But here is a list of the best foods I tried in Hanoi;

Pho

No visit to Hanoi is complete without sampling the iconic dish, pho. This noodle soup typically features beef or chicken, rice noodles, and a fragrant broth infused with herbs and spices. From street-side stalls to established restaurants, pho is a staple of Hanoi’s culinary landscape. As with most food in Vietnam, it’s also very cheap! I was often spending £1/2 per portion on the best Pho I’d ever had.

Bun Cha

Bun cha is a popular dish consisting of grilled pork patties, vermicelli noodles, and a bowl of sweet and savoury broth. It’s a favourite among locals and visitors alike, and is a must-try in you’re sampling Hanoi’s street food culture. I stumbled across a long like at a street food stall and tried Bun Cha for the first time! I don’t have a specific place to recommend but walk round the street markets (particularly at night) and you’ll find Bun Cha, among all sorts.

Egg Coffee

Egg coffee, or cà phê trứng, is a Hanoi specialty that has gained international acclaim. The rich and frothy concoction is made by whipping egg yolks with sweetened condensed milk and strong Vietnamese coffee. Served hot or cold, egg coffee is a big part of Vietnam’s coffee culture and is found pretty much anywhere in Hanoi. However, the original egg coffee can be found at Cafe Giang. Back when I visited Hanoi, I wasn’t a coffee drinker, so didn’t really enjoy the egg coffee. However, since moving to Melbourne, i’ve been converted and would love to go back and try egg coffee again.

Other foods to try are; noodle spring rolls (Phở cuốn), noodles with crab (Bún Riêu), fried fish (Cha ca La Vong), beef jerky with papaya (nộm bò khô) and Banh Mi (available throughout Vietnam).

Related Posts

hanoi travel guide

Exploring Hanoi: A Full Guide on the Best Things to Do

Hanoi, the capital of Vietnam, is a city where ancient traditions coexist with modern developments. Nestled along the banks of …
best things to do in hue

Best 6 Things to Do in Hue, Vietnam

Hue, the former imperial capital of Vietnam, is a city that resonates with historical significance and cultural richness. Found along …
hoi an old town

Exploring Hoi An, Vietnam

Hoi An, a charming town on Vietnam’s central coast, is a destination that seamlessly blends history, culture, and a relaxed …

The Best Things to do in Tam Coc, Ninh Binh

When people think of Vietnam, their minds usually go straight to the classic destinations; Hanoi, Ho Chi Minh City, Hoi …
Vietnam Visa

The Best Time to Visit Vietnam

Vietnam’s tropical monsoon climate brings diverse weather patterns across its three main regions, making the best travel time dependent on …

How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue

After an incredible 10 days in North Vietnam, it was time to start my journey down the country to Hue …

Visit Hanoi!!

Hanoi, with its blend of history, culture, and vibrant street life, offers a multifaceted experience for travellers. From the solemnity of the Ho Chi Minh Mausoleum to the lively chaos of the Old Quarter, each aspect of the city contributes to its unique charm. Hopefully this guide provides a good starting point for Hanoi and some inspiration on what to see! From Hanoi, I got a shuttle bus to Tam Coc and had a great few days exploring that region, before heading to Hue. I’d highly recommend visiting Tam Coc if you’re in the North of Vietnam, or as part of a North-South trip. I also have guides on the Vietnam visa process and the best time to visit Vietnam.

The post Exploring Hanoi: A Full Guide on the Best Things to Do appeared first on Char's Footsteps.

]]>
https://www.charsfootsteps.com/travel/asia/vietnam/exploring-hanoi-the-best-things-to-do/feed/ 0
Best 6 Things to Do in Hue, Vietnam https://www.charsfootsteps.com/travel/asia/vietnam/best-things-to-do-hue/?utm_source=rss&utm_medium=rss&utm_campaign=best-things-to-do-hue https://www.charsfootsteps.com/travel/asia/vietnam/best-things-to-do-hue/#respond Tue, 28 Nov 2023 10:32:26 +0000 https://www.charsfootsteps.com/?p=2684 Hue, the former imperial capital of Vietnam, is a city that resonates with historical significance and cultural richness. Found along the Perfume River, Hue boasts a collection of well-preserved ancient structures, providing a glimpse into Vietnam’s imperial past. This blog post will cover the best things to see in Hue and tips for when you’re […]

The post Best 6 Things to Do in Hue, Vietnam appeared first on Char's Footsteps.

]]>
Hue, the former imperial capital of Vietnam, is a city that resonates with historical significance and cultural richness. Found along the Perfume River, Hue boasts a collection of well-preserved ancient structures, providing a glimpse into Vietnam’s imperial past. This blog post will cover the best things to see in Hue and tips for when you’re there!

How to Get to Hue

Hue is a very easy city to get to! If you’re flying, Phu Bai International Airport is the nearest airport to Hue. Situated about 15km from the city center, the airport is well-connected to major Vietnamese cities, including Hanoi and Ho Chi Minh City. Taxis and airport shuttles are easy to catch for the short journey to the city.

If you’re exploring Vietnam by train, Hue’s railway station is a major stop on the North-South Railway. The station is close to the city center, allowing for easy access to accommodations and the main attractions. I highly recommend using the trains in Vietnam to travel around. I caught the overnight train from Ninh Binh to Hue – it was very comfortable and offered beautiful scenic views of the Vietnamese countryside. It was also very cost-effective, as the fare was reasonable and I didn’t have to pay for a night’s accommodation.

There are buses available, particularly from neighbouring cities like Da Nang and Hoi An. Although typically cheaper, the journey is usually longer depending on traffic conditions. Keep this in mind if you have limited time in Vietnam, or want to do Hue in a day trip.

How Long to Stay in Hue

Your time in Hue will depend on what you’re wanting to see and how long you have in Vietnam. I would recommend spending at least 1 night in Hue, giving you time to explore everything the city has to offer and enjoy some of the bars/restaurants. However, I wouldn’t personally recommend staying too long here. I originally booked to stay for 3 nights but left a day early. As I got the overnight train from Tam Coc / Ninh Binh, I arrived to Hue really early in the morning. By the following evening, I felt like I had seen most things and was ready to go. I did stay for two nights and made the most of a slow paced travel experience. Three nights seemed too long for what I wanted to do.

Best Things to Do in Hue

Imperial City / The Citadel

The Imperial City, a UNESCO World Heritage Site, stands as the focal point of Hue’s historical allure. Built in the early 19th century, the citadel served as the seat of the Nguyen emperors. Surrounded by walls and a moat, the vast complex includes the Forbidden Purple City, numerous temples, and ornate gates. While exploring the Imperial City, take in the architectural grandeur and the interesting history of the area. I would say the Citadel was the main attraction in Hue. I met other travellers who just did day trips to Hue, from nearby cities, and only focused on seeing the Citadel.

Thien Mu Pagoda

Perched on Ha Khe Hill along the Perfume River, Thien Mu Pagoda is an iconic symbol of Hue. Dating back to the 17th century, the pagoda is known for its seven-tiered tower and serene surroundings. The pagoda offers panoramic views of the river and the lush landscape, providing a tranquil escape from the bustling city. A visit to Thien Mu Pagoda allows for contemplation and appreciation of Vietnamese Buddhist architecture.

Tombs of the Nguyen Emperors

You’ll find Royal tombs dotted around Hue, each a testament to the unique architectural styles of the Nguyen Dynasty. The Tomb of Minh Mang, Tomb of Khai Dinh, and Tomb of Tu Duc are among the most renowned. These elaborate structures are set in picturesque landscapes, reflecting the emperors’ personalities and the cultural nuances of their respective eras. Exploring the royal tombs provides a glimpse into the imperial legacy and the artistry that defined the Nguyen period. Be sure to wear appropriate clothes that cover your shoulders and knees. You will be turned away if you arrive in strappy tops or skimpy clothing.

Dong Ba Market

For a taste of local life and an array of culinary delights, a visit to Dong Ba Market is essential. Located near the Perfume River, the market is a bustling hub where locals gather to buy and sell fresh produce, seafood, and traditional handicrafts. Navigating the vibrant stalls, you can sample delicious local delicacies and buy a vast array of fruit and vegetables. Although food dominates the market, you can also buy clothes, toys and souvenirs. Dong Ba Market offers an authentic glimpse into daily life in Hue and is an excellent place to engage with the local community.

Perfume River Boat Cruise

The Perfume River runs through the city of Hue, and is named so due to flowers falling into the river in Autumn, giving the river a perfume-like smell. Numerous operators offer guided boat tours that take you past Thien Mu Pagoda, the Imperial City, and the lush riverside landscapes. The boats are colourfully decorated and our tour guide provided interesting insights into the area’s history. Although this was a pretty ride, I think I was a little let down after seeing how beautiful the river boat rides were in Tam Coc.

The Food Scene in Hue

I am a big foodie, so I couldn’t wait to try the delicacies that are local to Hue. There are a number of good restaurants, bars and markets to choose from, but some of my favourite dishes here were;

Bun Bo Hue

A signature dish of the region, bun bo Hue is a flavorful noodle soup featuring beef, lemongrass, and a vibrant broth. The dish often includes pork knuckles, congealed pig blood, and a medley of fresh herbs, creating a harmonious blend of textures and tastes.

Banh Khoai

Similar to a crispy pancake, banh khoai is a savoury delight made with rice flour, water, and turmeric. Stuffed with shrimp, pork, and bean sprouts, the pancake is folded and served with a tangy dipping sauce. It seems to be primarily a street food dish, as I couldn’t find it in restaurants.

Nem Lui

Nem lui, or grilled pork skewers, is a popular dish in Hue. Minced pork is seasoned with lemongrass, garlic, and chili before being molded onto bamboo sticks. Served with rice paper, fresh herbs, and a dipping sauce, nem lui was one of my favourite dishes in Hue.

Hue, with its imperial grandeur and cultural tapestry, stands as a great place to visit for those seeking a deeper understanding of Vietnam’s history. From the imposing walls of the Imperial City to the serene banks of the Perfume River, each corner of Hue tells a fascinating story of a bygone era. Hue is definitely a destination worth visiting, however, I wouldn’t recommend staying too long here. From Hue, I made my way to Hoi An via bus.

The post Best 6 Things to Do in Hue, Vietnam appeared first on Char's Footsteps.

]]>
https://www.charsfootsteps.com/travel/asia/vietnam/best-things-to-do-hue/feed/ 0
Exploring Hoi An, Vietnam https://www.charsfootsteps.com/travel/asia/vietnam/exploring-hoi-an-vietnam/?utm_source=rss&utm_medium=rss&utm_campaign=exploring-hoi-an-vietnam https://www.charsfootsteps.com/travel/asia/vietnam/exploring-hoi-an-vietnam/#respond Mon, 27 Nov 2023 12:29:26 +0000 https://www.charsfootsteps.com/?p=2670 Hoi An, a charming town on Vietnam’s central coast, is a destination that seamlessly blends history, culture, and a relaxed atmosphere. Known for its well-preserved ancient architecture, vibrant lantern-lit streets, and incredible local cuisine, Hoi An is a must-visit for those seeking an authentic Vietnamese experience. I was lucky enough to stay here for 5 […]

The post Exploring Hoi An, Vietnam appeared first on Char's Footsteps.

]]>
Hoi An, a charming town on Vietnam’s central coast, is a destination that seamlessly blends history, culture, and a relaxed atmosphere. Known for its well-preserved ancient architecture, vibrant lantern-lit streets, and incredible local cuisine, Hoi An is a must-visit for those seeking an authentic Vietnamese experience. I was lucky enough to stay here for 5 nights during my month trip in Vietnam and LOVED it! In this blog, I hope to provide tips on planning your trip to Hoi An; including how to get there, how long to stay, and the best things to do in Hoi An.

How to Get to Hoi An

Hoi An is easily accessible by various means of transportation. If you’re arriving by air, Da Nang International Airport is the nearest major airport, approximately 30km away. From the airport, take a taxi or a pre-arranged shuttle to reach Hoi An. This journey will take roughly 45 minutes.

For those traveling by train, the nearest railway station is in Da Nang as well. From Da Nang, you can take a short bus or taxi ride to Hoi An. If you’re travelling light, I’d recommend getting a grab taxi bike. That way you can weave through the traffic.

Although buses can take a little longer, cities like Hoi An are very well-connected to other major cities, like Hue and Da Nang, via a reliable bus network. I took the bus from Hue to Hoi An, which was a cheap and comfortable option. The bus had three rows of seats and were two-story – it looked quite intense when I first boarded. However, there’s space to lie down, so I snoozed and watched pre-downloaded Netflix shows.

How Long to Stay in Hoi An

The ideal duration of your stay in Hoi An largely depends on your travel preferences, interests and budgets. However, I’d recommend staying 3-4 days to fully immerse yourself in the town and explore its highlights without rushing.

This timeframe allows you to stroll through the ancient streets, savour the diverse culinary offerings, and take part in any cultural events or activities that might be happening during your visit. Additionally, it provides ample time to venture beyond the town and explore the surrounding areas. Hoi An was truely one of my favourite places to visit in Vietnam, so i’d recommend allocating a few days here.

Best Things to Do in Hoi An

The Ancient Town of Hoi An

Hoi An’s Ancient Town, a UNESCO World Heritage Site, is the heart of the city and a treasure trove of historical architecture. The town’s well-preserved buildings, dating back to the 15th century, showcase a unique blend of Vietnamese, Chinese, and Japanese influences. The narrow, winding streets are best explored on foot or by bike, allowing you to appreciate the intricate details of the architecture and the atmosphere of the town.

While exploring Ancient Town, make sure to visit the iconic Japanese Covered Bridge, a symbol of Hoi An. Originally constructed in the 1590s, this bridge connects two districts and is adorned with a small temple. It’s a testament to the town’s historical significance as a trading port.

The whole area is stunning, but especially so at night, when the Ancient Town comes alive with lanterns and lights. There are many eateries and bars around this area, so it’s definitely worth coming here to eat. You’ll also find a few street markets stalls around here selling local delights and desserts, which are worth checking out. Throughout my stay in Vietnam, I never had any stomach issues. Although, I appreciate people can get nervous about eating street food, it appeared safe!

Central Food Market

Hoi An has a few different markets worth checking out, however as a foodie, my favourite was the Central Food Market. This market is an excellent place to try a variety of Vietnamese street food. From Vietnamese classics, like pho or banh mi, to more unique foods, there’s a variety of things to choose from. As it’s very reasonably priced, I liked coming here a try a little of everything to see what I liked. You’ll be able to get a glimpse into the vendor’s daily life, selling fresh produce, spices, and handmade crafts.

An Bang Beach

An Bang Beach is a serene stretch of coastline, located a short bike ride or taxi from the town center. Compared to other beaches in Vietnam, An Bang offers a much quieter atmosphere, making it an ideal spot to unwind. You can rent a beach chair, sip on coconut water, and enjoy the sound of the waves. The beach is dotted with small seafood restaurants where you can indulge in fresh catches of the day. My hostel offered bicycles to rent for the day which I’d highly recommend doing! You can find bicycle rental shops dotted around the city, offering really reasonable day rates.

Get Some Clothing Tailored

Hoi An’s Ancient Town has become famous for being a great place to get high quality, tailoring done quickly, and at affordable prices. With over 500 tailors, you’ll be spoilt for choice in Hoi An. I didn’t get anything tailored personally. However, I met many backpackers who were staying in Hoi An for a few days, whilst they got clothes tailored. This include people getting authentic Vietnamese dresses made, all the way to a guy getting his wedding suit tailored! Recommendations I got from other travellers included shopping around, instead of sticking with the first shop you walk into. Additionally, get to the tailors early in your trip, so they have enough time to get your clothing made.

Yoga and Wellness

If you’re looking to unwind, there are a range of gyms, yoga and wellness studios dotted around Hoi An. My hostel was located near a few good gyms which offered cheap day passes. This was the perfect chance to do a few workouts after weeks of just eating! Hoi An is also home to some great yoga studios. I went to Om Factory several times and loved the welcoming atmosphere and relaxing sessions, after busy days of sightseeing.

A Day Trip to My Son Sanctuary

For those wanting to learn more about the area’s history, consider doing a day trip to My Son Sanctuary. Located about 40km southwest of Hoi An, My Son is a cluster of abandoned Hindu temples dating back to the Champa Kingdom. Despite the damage caused during the Vietnam War, the site still holds archaeological and historical significance. I’d really recommend doing a guided tour! The guides are very knowledgable and help provide good understandings of the rich cultural heritage of this ancient religious center.

The Food!

Hoi An is renowned for its incredible cuisine, and no visit is complete without sampling some of the local dishes. From the savoury cao lầu noodles to the iconic white rose dumplings, the town’s culinary scene is worth spending a few days exploring! Here are some dishes not to miss if you’re in Hoi An.

Reaching Out Teahouse

The Reaching Out Teahouse was a very special place during my visit to Hoi An. Despite being located within the bustling streets of the Old Town, the Reaching Out Teahouse is a serene, peaceful environment. What makes it so special, are the people who work there. This teahouse only employs individuals with speech and hearing impairments and it encourages a quiet environment. There are traditional Vietnamese tea and coffee tastings to enjoy, along with great cookies! Such a lovely atmosphere and I sat here twice to take in the peaceful environment.

Cao lầu

Cao lầu is a noodle dish unique to Hoi An, featuring thick rice noodles, slices of pork, and crispy croutons, in a tasty broth. The dish is then topped with fresh herbs and greens. You’ll be able to easily find this dish throughout Hoi An’s Ancient Town and it’s definitely worth a try.

White Rose Dumplings

White rose dumplings are made from translucent rice paper and are filled with a mixture of minced shrimp and spices. They’re lightly steamed and often served with a dipping sauces – so tasty! Again, these are a speciality in Hoi An, so you should be able to find them quite easily. I first tried them at the Hoi An Central Market and had them again at the White Rose Dumpling Restaurant.

Banh Mi

Banh Mi is a popular Vietnamese sandwich that you’ll see throughout Vietnam. It’s effectively a baguette, with a variety of fillings (grilled pork, pate etc) and veggies. I lost count of how many I ate during my month in Vietnam, but the best one I had was at Banh Mi Phuong! This spot has risen to fam for its incredible Banh Mi, and it’s worth visiting if you’re travelling here.

Hoi An was one of the most magical places I visited during my trip to Vietnam. With its rich history, cultural diversity, and amazing food, is a captivating destination filled with authenticity and charm. Whether you’re exploring the ancient streets, savouring local delicacies, enjoying the quiet beaches or soaking in the laid-back atmosphere, Hoi An offers something for everyone! Another must-do in Vietnam, is the hidden gem of Tam Coc!

The post Exploring Hoi An, Vietnam appeared first on Char's Footsteps.

]]>
https://www.charsfootsteps.com/travel/asia/vietnam/exploring-hoi-an-vietnam/feed/ 0
The Best Things to do in Tam Coc, Ninh Binh https://www.charsfootsteps.com/travel/asia/vietnam/tam-coc/?utm_source=rss&utm_medium=rss&utm_campaign=tam-coc https://www.charsfootsteps.com/travel/asia/vietnam/tam-coc/#respond Sat, 15 Oct 2022 12:16:33 +0000 https://www.charsfootsteps.com/?p=368 When people think of Vietnam, their minds usually go straight to the classic destinations; Hanoi, Ho Chi Minh City, Hoi An! However, the hidden gem of Tam Coc was probably one of my favourite places in Vietnam! It’s an ideal place to relax for a few days and unwind from the hectic, hussle & bustle […]

The post The Best Things to do in Tam Coc, Ninh Binh appeared first on Char's Footsteps.

]]>
When people think of Vietnam, their minds usually go straight to the classic destinations; Hanoi, Ho Chi Minh City, Hoi An! However, the hidden gem of Tam Coc was probably one of my favourite places in Vietnam! It’s an ideal place to relax for a few days and unwind from the hectic, hussle & bustle of Hanoi.

Tam Coc is home to some of the most stunning sights Vietnam has to offer and is definitely worth visiting during your time in the north! Known as ‘Ha Long Bay on land’, Tam Coc is part of the Trang An complex, a UNESCO World Heritage Site. Although Ninh Binh is larger, with more amenities, the real charm of the area lies in Tam Coc! Here is a guide on how to have a great time in Tam Coc.

Tam Coc

Best Things to do in Tam Coc

There are a number of great things to see during your trip to Tam Coc, including;

  • Hang Mua (Mua Caves)
  • Bich Dong Pagoda
  • Trang An Landscape Complex
  • Tam Coc Boat Tour
  • Thai Vi Temple

If you’re short on time in Tam Coc, I recommend the Mua Caves and Trang An Landscape Complex as definite must-dos!

Powered by GetYourGuide

Hang Mua

Without doubt, Hang Mua (Mua Caves) was the highlight of my trip to this region. Climbing the 500 steps to Hang Mua Peak will give you breathtaking, 360 degree views of the stunning countryside and rice paddies. The climb itself isn’t too challenging, however the heat and humidity make it tough. I went at midday (bad planning!) and it was hot! Take it slow and bring water. There are a few steep bits, but as someone who is terrified of heights, I was ok.

Hang mua peak

The caves themselves can be found at the bottom of the mountain. I think these were less spectacular, so I recommend go straight for the hike!

The Hang Mua Peak actually consists of two peaks. I recommend leaving enough time to climb both, as they offer different views and experiences. Luckily you won’t have to climb each from ground level, as the split for the two peaks is near the top. You’re only have 100 steps, or so, to get to the top.

The highest peak (which most people do) is home to a stone carved dragon, that watches over the valley. It plays an important role in Vietnamese culture, with locals believing it’s crucial for rain and agriculture. The views from here are incredible! I was fortunate that it was too busy when I went…probably as I chose the hottest time of day to go. But I heard from people who went early in the morning, or near sunset, that it was packed at this main peak.

The smaller of the two peaks provides just as breathtaking of a view. The bonus of this peak was it’s much quieter nature than the main one. However, there were sections of the steps that were very narrow. This made it challenging to go at a comfortable pace, if people behind were racing up. The Pagoda at the top of the smaller peak provides a great photo opportunity.

Hang mua caves

Getting to Hang Mua is easy. With it being 4-5km away from Tam Coc, you can easily cycle, scooter or grab a taxi there. Be careful of scammers here! Parking is right up the entrance gate and FREE. Ignore the guys trying to scam 20-50k per bike and ride past them to the entrance.

The entrance fee to Hang Mua is 100k vnd per person and free for children under 1m tall. Once you’re through the entrance you’ll find a lodge, where people stay to access the caves before the typical crowds arrive. Around here is also a restaurant and a few shops that sell drinks, snacks and souvenirs.

Bich Dong Pagoda

Hidden amongst mountains and natural caves, Bich Dong Pagoda is comprised of 3 ancient pagodas. Situated 2km west of Tam Coc, it’s easy to access via bicycle or scooter. You’ll be met with a grand entrance upon arrival (photo below), surrounded by lily-filled waters. Pass through the entrance and you’ll find the 3 pagodas up around 100 steps. Take your time exploring each one.

Bich dong pagoda

As with anything deemed as ’insta-worthy’, expect there to be queues of people taking photos in the entrance way. To avoid queues, and the midday heat, I’d recommend visiting early (6-8am) or during sunset. You’ll also benefit from the colourful skies overlooking the mountains during the evening!

It’s free to enter the Pagodas, however, expect to pay a small fee for parking.

Trang An Landscape Complex

The Trang An Scenic Landscape Complex was inscribed as a UNESCO World Heritage Site in 2014 for both cultural and natural values. Spanning 6,268ha, the complex covers jaw-dropping limestone mountains, tranquil rivers and an impressive collection of ancient pagodas and temples.

Exploring this complex is done via the river – with three routes to choose from! You hire a boat with a local rower and the tours take 2-3 hours. Google ’Trang An Grottoes Tour’ or ‘Trang An Departure Boat Ticket’ to find tickets and where the boats depart. Tickets cost 200,000vnd per person and you’ll have up to 4 people per boat.

This scenic trip will take you through caves, valleys and temples – a number of which can only be reached this way! As temples are sacred places in Vietnam, you must wear appropriate clothes that cover legs and shoulders.

A list of places you can expect to visit include the Trinh Temple, Tran Temple, Toi Cave (dark cave), Sang Cave (light cave), Nau Ruou Cave, Dia Linh Cave and Suoi Tien Temple. Trang An also happened to be a major filming site for the movie Kong: Skull Island. You can visit this film set during certain tours.

Trang an tam coc
Map showcasing the different routes.

Tam Coc Boat Ride

Another boat trip worth doing is one from Tam Coc, around the NGO Dong River and through the limestone mountains. The trip is 3km long and you’ll pass through 3 limestone caves in the mountains. Although it’s not as impressive as the Trang An trip, the relaxing ride around the Ngo Dong River is worth doing.

Tam Coc translates to the ’three caves’ – Hang Ca, Hang Hai and Hang Ba. You’ll visit these along the Ngo Dong River. The first cave is the longest – at 127m. Here you’ll be met with a cool climate and stalactites hanging from the ceiling! After finishing here, you’ll travel slowly 1km down the river to the second cave. It’s smaller at 60m but still has many stalactites to admire. The third, and last cave, is much shorter (50ish m) and is much lower.

Tam coc river boat

The entry fee is divided into two tickets – one to visit the landscape (120,000vnd) and one for the boat ride (75,000vnd). Child tickets were 100,000vnd. The boats are quite small, and it ended up being just two of us on my ride.

Some tips for the day: You’ll be sat for quite a while, often in the direct sunlight, so come equipped with sun protection (cream/hats etc). There was a chance to buy drinks at the return point, but we were glad to have brought water with us given the heat. We stopped halfway round to be shown a series of bags and hand embroidered table clothes. We were made to wait here a while until they gave up trying to sell to us.

Be sure to tip the rower too as they’re peddling for hours with their feet in the heat! Our guide was very knowledgable and gave us a great experience.

Covid update: I did this ride pre-covid. However, there are reports of ‘surcharges’ if you want more than two adults and two children in the boat.

Thai Vi Temple

Thai Vi Temple is an ancient temple dating back to the 13th century. Here you’ll be able to get an understanding of the Tran Dynasty; with some of it’s architecture and artefacts. It’s fairly small, so it won’t take long to see. Afterwards, you can enjoy a cycle or walk around the surrounding areas of rice paddies, peaceful fields and limestone mountains

It’s located less than 1.5km from Tam Coc, making it walkable from the town centre. If you’re planning to do a Trang An boat tour, you can visit Thai vi on the way!

Make sure to cover your knees and shoulders out of respect when visiting the temple. There is no entrance fee, but if you plan to cycle, you’ll need to bring some change for the parking.

How to Get to Tam Coc

Located in North Vietnam, Tam Coc is approximately 90km south of Hanoi. There are several ways to get to Tam Coc including shuttle bus, train, taxi and motorbike.

As my month in Vietnam started in Hanoi, I took a 2 hour shuttle from my hostel in the Old Quarter straight to Tam Coc. I organised it through a agency near my hostel in Hanoi’s Old Quarter, but most accommodations and local agencies can help with this. They seem to offer similar services and prices. The shuttle was spacious, comfortable, with capacity for 10 and free water was provided. Shuttles go to both Tam Coc and Ninh Binh.

There are bus and train options. For the latest information, check out this Hanoi to Ninh Binh schedule. Factor in the extra cost and time to travel from Ninh Binh to Tam Coc.

Given how easily accessible it is from Hanoi and Ninh Binh, expect to see frequent day tours here. The evenings are typically quieter, usually only occupied by the travellers staying in the area.

Note:

Vans and shuttles will likely drop you at a taxi point, central to town. As they’re too big to drive down the winding path along the river, be prepared to walk with your bags if you’re staying somewhere there. It’s an easy, short walk to the other side (10 minutes max) – but it’s an added journey in the heat with backpacks. Surprisingly a car was able to get down the narrow path to collect me for my train to Hue.

Getting around Tam Coc

During my stay, I hired a bicycle from my homestay. If your accommodation doesn’t provide this option, there are shops along the main strip that rent bicycles. Bicycle helmets often weren’t provided, unless you hired a scooter.

Hiring a scooter is another great way to explore the area easily. Given how quiet the area is, it’s much safer than riding in any of the Vietnamese cities.

An alternative would be to hire a taxi for the day and be driven around all the main sights. This doesn’t quite give you the same flexibility as bicycles or scooters, but is convenient and takes the stress out of map reading!

The Best Time to Visit

The best time to visit Tam Coc would be during spring or autumn – where temperatures aren’t too high and conditions are drier. North Vietnam has defined summers and winters. Winter months are between November and April, with temperates ranging from 17-22°C and limited rainfall. Summer months fall between May and October, bringing very hot and humid weather. The wettest months are between July and September.

Places to stay in Tam Coc

There are numerous hotels and hostels dotted around, but the real heart of Tam Coc can be found in the many homestays! After many recommendations in Hanoi from people arriving from Tam Coc, I decided to cancel my hostel reservation and go for my first homestay in Vietnam.

I booked at the Tam Coc Lake View. Although the accommodation was very basic, I loved being able to stay with a local family. They were fantastic at recommending local things to do and they loaned bicycles cheaply to explore more far afield places. I did find it harder to meet other travellers though, so I would suggest solo backpackers to take this into consideration when booking.

Where to eat in Tam Coc

For such a small town, Tam Coc does have a generous number of restaurants and bars. During my short stay, I loved Vinteca Bar and Chookies Beer Garden for drinks! Both offered great vibes and were reasonably priced.

If you’re at a homestay, it’s worth seeing if the hosts are organising anything in the evening. Although my homestay didn’t, I met a few people who had hosts organise a large dinner for all guests for a small fee. I would imagine this is a great way to meet other backpackers whilst getting to know more about the local area.

Otherwise I would recommend strolling on the ‘main strip’ where the majority of bars and restaurants are. Most seating is out at the front of the restaurant so you can gauge a vibe of each place and what food they have to offer. One of my favourite places to eat along here was at Ngoc Ninh – great food, lovely owners and a free beer during happy hour!

Other Tips for Tam Coc

Mosquitos

Bring ample supplies of anti-mosquito spray! As you’re around a lake, the mosquitos are rife! After a brief 8-10 minute walk to my homestay from dinner one night, I found many dead mosquitos stuck to my leg from basically walking into them. So gross!! Dengue fever is present in Vietnam; peaking between April and October in the North, and June through to December in the south. There isn’t a widely available vaccination for this, and the one that does exist, is typically only given to people who previously had dengue. So I was very aware of that and went through bottles of heavy duty DEET to protect myself.

If possible, bring a mosquito net. Every hostel, homestay and hotel I stayed at throughout my time in Vietnam provided mosquito nets. However some were quite worn and I didn’t feel protected. If you have one that’s easy to pack, there’s no harm having extra protection.

Cash

Make sure to bring plenty of cash. There are ATMs, but they’re outside the main part of Tam Coc. This might not be an issue if you have a scooter to get round easily. But they’re not always easy to access and I wouldn’t want to rely on the one ATM in the area. Hanoi has plenty of ATMs, banks and cash converter stalls so make sure to stock up before you go.

After my incredible few days in Tam Coc, I made the long journey to from Ninh Binh to Hue on overnight train. I was quite nervous about this journey but it was brilliant AND I saved a full day of travel and money on a hostel. Tam Coc was definitely a highlight during my time in Vietnam, but I also LOVED Hoi An. I have other. guides on how to apply for a Vietnam Visa and the best time to visit Vietnam.

Related Posts

hanoi travel guide

Exploring Hanoi: A Full Guide on the Best Things to Do

Hanoi, the capital of Vietnam, is a city where ancient traditions coexist with modern developments. Nestled along the banks of …
best things to do in hue

Best 6 Things to Do in Hue, Vietnam

Hue, the former imperial capital of Vietnam, is a city that resonates with historical significance and cultural richness. Found along …
hoi an old town

Exploring Hoi An, Vietnam

Hoi An, a charming town on Vietnam’s central coast, is a destination that seamlessly blends history, culture, and a relaxed …

The Best Things to do in Tam Coc, Ninh Binh

When people think of Vietnam, their minds usually go straight to the classic destinations; Hanoi, Ho Chi Minh City, Hoi …
Vietnam Visa

The Best Time to Visit Vietnam

Vietnam’s tropical monsoon climate brings diverse weather patterns across its three main regions, making the best travel time dependent on …

How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue

After an incredible 10 days in North Vietnam, it was time to start my journey down the country to Hue …

The post The Best Things to do in Tam Coc, Ninh Binh appeared first on Char's Footsteps.

]]>
https://www.charsfootsteps.com/travel/asia/vietnam/tam-coc/feed/ 0
The Best Time to Visit Vietnam https://www.charsfootsteps.com/travel/asia/vietnam/best-time-visit-vietnam/?utm_source=rss&utm_medium=rss&utm_campaign=best-time-visit-vietnam https://www.charsfootsteps.com/travel/asia/vietnam/best-time-visit-vietnam/#comments Thu, 21 Jan 2021 21:48:47 +0000 https://www.charsfootsteps.com/?p=411 Vietnam’s tropical monsoon climate brings diverse weather patterns across its three main regions, making the best travel time dependent on your destinations and activities. If you’re planning a multi-regional trip, be prepared for a mix of conditions. While there’s no “wrong” time to visit Vietnam, understanding seasonal patterns helps in planning around the region’s wet, […]

The post The Best Time to Visit Vietnam appeared first on Char's Footsteps.

]]>
Vietnam’s tropical monsoon climate brings diverse weather patterns across its three main regions, making the best travel time dependent on your destinations and activities. If you’re planning a multi-regional trip, be prepared for a mix of conditions. While there’s no “wrong” time to visit Vietnam, understanding seasonal patterns helps in planning around the region’s wet, dry, and peak weather times. The best time to visit Vietnam will largely depend on which part of the country you’re visiting and what you intend to do. I went to Vietnam for a month in October and during my trip from Hanoi down to HCMC, I experienced a mix of everything!

North Vietnam: Hanoi, Ha Long Bay & Sa Pa

Northern Vietnam experiences a distinct winter and summer, with varying weather across its plains, coastal areas and highlands.

November to April (Dry Winter): The cooler, drier season with average temperatures between 17-22°C. January to March are the coldest months, especially in mountainous regions.

May-October (Hot & Rainy): Northern Vietnam heats up with higher humidity and rainfall, peaking between July and September. Expect frequent showers and warmer temperatures.

Places to Visit in North Vietnam & Timing Tips

North Vietnam is famous for its many UNESCO World Heritage sites, northern capital Hanoi and its mountainous, trekking regions like Sa Pa and Mu Cang Chai.

Hanoi, Tam Coc, Ha Long Bay, and Ninh Binh: October-November or April-May offers mild temperatures and avoids peak rainfall and winter chills. I visited this region in October, where I had temperatures of 30°C and no rain!

Sa Pa, Ha Giang, and Mu Cang Chai: Temperatures in these higher regions are cooler year-round, averaging 15-28°C in the day and 10-18°C at night. Winter months are chilly and summer brings rain. You can cycle and hike all year round in these regions, but expect it to be chilly in the winter months and very rainy in the summer.

Related posts: Tips for Catching the Sleeper Train from Tam Coc/Ninh Binh to Hue

Central Vietnam: Hoi An, Da Nang, Hue and Dalat

Central Vietnam sees a long dry season and a shorter, intense rainy period with some typhoon risks.

January to August (Hot and Dry): Central regions experience extended dry spells with temperatures between 21°C and 35°C. July and August are often the hottest months.

September to December (Rainy Season): September brings heavy rains, particularly in October and November, when typhoons are most likely.

Places to Visit in Central Vietnam & Timing Tips

Visiting the central highlands, like Dalat, will need some planning. The heavy rainfall from June to October makes doing any of the outdoor activities it’s known for, pretty difficult. During my visit in November, all hiking routes were closed and we spent our time exploring the Crazy House in the torrential rain. Be sure to bring layers and waterproofs, as it does get quite cold!

Hoi An, Hue & Da Nang: Visit between January and August for clear, dry weather perfect for beach and sightseeing activities. During this time you’ll have very hot days of mid-30s and high humidity. Typhoons are possible later in the year, especially October to November.

Dalat: Rain peaks between June and October, making it challenging for outdoor activities. The cool highland temperatures mean layers and waterproofs are essential, especially during the rainy season.

Nha Trang: This coastal area enjoys longer dry periods from January to September. Rainy season from October to December can bring occasional downpours, but it’s less intense than elsewhere in Central Vietnam.

South Vietnam: Ho Chi Minh City, Mekong Delta & Phu Quoc

The South is warm year-round with a dry and rainy season, each bringing its own charm to the region.

November to April (Dry Season): This is the peak travel time in South Vietnam, with warm but drier conditions. This is particularly ideal for outdoor exploration!

May to October (Rainy Season): High humidity and frequent afternoon rain showers are the norm. June to August is the wettest period, but rain often comes in short bursts, allowing activities to resume afterward.

Places to Visit in South Vietnam & Timing Tips

Ho Chi Minh City, Mekong Delta and Coastal Resorts (Mui Ne, Long Hai): November to April offers clear skies and moderate humidity. Rainy season can be unpredictable but it’s typically sunny in the morning and rain in the afternoons. During my month in Vietnam, I made it to HCMC by November where we had the odd burst of rain.

Phu Quoc and Con Dao Islands: These islands are mostly sunny year-round but do experience brief rain showers in the wet season. Dry season (December to March) is ideal for staying here and doing beach activities. I didn’t have time to visit Phu Quoc during my month in Vietnam but heard amazing things about it!

Vietnam’s climate diversity makes planning around the weather something to factor in for a great trip. From exploring mountain trails in the North to enjoying beach days in the South, timing your visit by season will help you make the most of each region. As Vietnam is so big, with so much to explore, I would recommend either choosing a region (like north or south) based on the time of year. Or if you want to do the full length, like I did, choose the direction based on the rain season. I’ve also got a guide on how to apply for a Vietnam Visa depending on how long you want to go for and how many entries you need.

Related Posts

hanoi travel guide

Exploring Hanoi: A Full Guide on the Best Things to Do

Hanoi, the capital of Vietnam, is a city where ancient traditions coexist with modern developments. Nestled along the banks of …
best things to do in hue

Best 6 Things to Do in Hue, Vietnam

Hue, the former imperial capital of Vietnam, is a city that resonates with historical significance and cultural richness. Found along …
hoi an old town

Exploring Hoi An, Vietnam

Hoi An, a charming town on Vietnam’s central coast, is a destination that seamlessly blends history, culture, and a relaxed …

The Best Things to do in Tam Coc, Ninh Binh

When people think of Vietnam, their minds usually go straight to the classic destinations; Hanoi, Ho Chi Minh City, Hoi …
Vietnam Visa

The Best Time to Visit Vietnam

Vietnam’s tropical monsoon climate brings diverse weather patterns across its three main regions, making the best travel time dependent on …

How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue

After an incredible 10 days in North Vietnam, it was time to start my journey down the country to Hue …

The post The Best Time to Visit Vietnam appeared first on Char's Footsteps.

]]>
https://www.charsfootsteps.com/travel/asia/vietnam/best-time-visit-vietnam/feed/ 9
How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue https://www.charsfootsteps.com/travel/asia/vietnam/ninh-binh-to-hue/?utm_source=rss&utm_medium=rss&utm_campaign=ninh-binh-to-hue https://www.charsfootsteps.com/travel/asia/vietnam/ninh-binh-to-hue/#comments Mon, 18 Jan 2021 20:38:20 +0000 https://www.charsfootsteps.com/?p=387 After an incredible 10 days in North Vietnam, it was time to start my journey down the country to Hue. My travel options included flying from Hanoi, or taking a sleeper bus or train from Ninh Binh. After much debate, I decided on the sleeper train. As I was in Tam Coc, this seemed to […]

The post How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue appeared first on Char's Footsteps.

]]>
After an incredible 10 days in North Vietnam, it was time to start my journey down the country to Hue. My travel options included flying from Hanoi, or taking a sleeper bus or train from Ninh Binh. After much debate, I decided on the sleeper train. As I was in Tam Coc, this seemed to be the easiest and cheapest way to travel down to Central Vietnam.

Although the average flight time between Hanoi and Hue is 1hr 15 min, it sounded like a logistical nightmare coming from Tam Coc. It would involve a shuttle back to Hanoi, transport to Hanoi’s airport and then a flight. Aside from the financial cost of this, there was the added cost of wasting half a day travelling. This option didn’t appeal to me.

Tam Coc ninh binh to hue
Soft sleeper

Vietnam Sleeper Trains

The sleeper train starts in Hanoi and goes straight to Hue, via Ninh Binh. As soon as I discovered this, it was a no brainer. It covers the 575km journey in 11.5 hours and cost me $25USD. I bought a soft sleeper 4-berth ticket, that would allow me to sleep through most of the trip.

The train was fairly empty, so I could choose whether I wanted a lower or upper berth ticket. As I was planning my trip as I went along, I felt fortunate to be able to buy my ticket the day of my travel. However, if you’re going in peak season, consider buying your ticket a few days in advance at least.

I organised the whole journey through a hostel in Tam Coc, near my homestay. They were unbelievably helpful in explaining the different options available. Additionally, they gave me my ticket (saving time at the station) and organised a taxi to collect me from my homestay. You must reserve a ticket in advance. Booking opens 60 days before departure, sometimes even 90 days before.

Notes: Children aged 0-4 travel for free. Children between 5-9 travel at 25% off. Children 10+ are full fare.

Check out this site for a full timetable of trains from Ninh Binh to Hue and any other train route in Vietnam.

Powered by GetYourGuide

The Different Trains in Vietnam

There are typically 5 different seat options you have on a Vietnam Train. For long, overnight journeys like Ninh Binh/Tam Coc to Hue, opt for a sleeper:

Soft sleepers with AC: Soft sleepers usually have 4 beds (berths), two on either side, with a table included. Expect air-con, power sockets, a water dispenser in the carriage, toilets, luggage space and meals (extra cost). I went with option, which you can see in the picture above. The quality of these beds/cabin will largely depend on how modern the train is. I luckily got a new train, so the beds were quite comfortable and everything felt very clean. Modern trains also have a VIP option with just two beds.

Hard sleepers with AC: Hard sleepers have 6 berths; lower, middle and top on each side of the cabin. The facilities are actually the same as the soft sleeper in terms of air-con, power sockets, toilets, luggage, food etc. The only difference is the two extra beds.

Soft seats with AC: Similar to what you would find on an airplane, these are cushioned seats that can recline a bit. They’re usually located in modern carriages, with air-con and power sockets. These are fine for day trips, but for the small difference in price, you’re better off upgrading to one of the sleeper options for overnight or long journeys.

Hard seats with AC: As the name suggests, these are hard, wooden, upright seats in modern carriages with air-con. For a journey as long as Ninh Binh to Hue, these would be less than ideal.

Ordinary hard seats: These consist of wooden, upright seats in old carriages without air-con. Aside from being super cheap, the advantage of this carriage is the windows open. Making them perfect for photography. Although, this wouldn’t be a recommended option for an overnight or long journey.

For sleeper trains, you would typically choose between air-conditioned soft and hard sleepers. This will be dependant on your budget and how many people are in your group.

Day of Travel & Ninh Binh Station

On the evening of the journey, I had dinner in a local restaurant in Tam Coc. After another incredible pork pho (and free happy hour beer) I went back to my homestay to wait for my 9pm taxi. My train wasn’t until 10:12pm, so I had to wait around my homestay for a while. Soon enough, a taxi arrived with a few people from the hostel I had booked at. They had kindly gone out their way to collect me!

I was surprised it could drive down the tiny, narrow paths around Tam Coc lake to where my homestay was located, but very relieved it did. With only 5km between Tam Coc and Ninh Binh, we arrived promptly at Ninh Binh Railway Station.

The station was bustling with a mix of locals and travellers. This was a relief as I was concerned about waiting alone at night or getting on the right train. Expect very basic facilities in terms of toilets and the one small shop selling water.

Ninh Binh to Hue Sleeper Train

As the time approached for the train’s arrival, everyone was ushered towards the platform. Once it had arrived, everyone piled on. It did wait for about 10 minutes to give everyone a chance to find their correct carriage.

I was pleasantly surprised with my cabin. It was clean, spacious and I had it to myself! I did spend the night wondering if anyone would be joining me throughout the long journey. But it remained empty the entire way, which was a huge bonus.

I slept for the majority of the 11.5 hours, occasionally waking briefly when the train stopped. Although it was comfortable, it was FREEZING! I recommend packing extra layers, like jumpers. The train arrived in Hue at 9:35am. I was staying on the other side of the city, so took a $2USD scooter taxi to my hotel. All in all, it was an incredible painless journey. It was logistically very easy, cheaper than flying and it freed up an extra day of sight-seeing.

Bus from Tam Coc to Hue

The other option of travelling between Ninh Binh and Hue is to take a sleeper bus. Surprisingly, the bus is a similar journey time. However, the sleeper train sounded more comfortable and wasn’t much more expensive than the bus. Once in Hue, I met people who said they found the sleeper bus uncomfortable and scary at points. I didn’t want to arrive in Hue exhausted, after a terrible night’s sleep, and potentially ruin a day of exploring. I was very happy with my choice of sleeper train.

Tips for Taking a Vietnam Sleeper Train

Buy tickets in advance: booking open 60 days (sometimes 90 days) before departure. All trains require a reservation, as they’ll print your train number, carriage number and seat/berth on the ticket. This is especially important during peak seasons, such as Tet: Vietnamese New Year (end of Jan/Feb).

Bring layers! The sleeper trains are really cold! I left Tam Coc in shorts and t-shirt, given the heat and humidity. Luckily I had my cabin to myself for the entire journey and had my backpacks with me. So I was easily able to get changed and put on lots of layers but if you’re sharing with strangers this might be harder.

Buy Water and Snacks ahead of time. There is a small shop at the station but I would strongly advise you to eat a proper meal ahead of time and to bring your own snacks and water. There is a kitchen on board that serves meals for $2. However, this depends on which seat-type you choose and is hard to have on overnight journeys.

Use blankets/towels over the sheets. My bed hadn’t been slept in but I had heard horror stories about sheets being dirty. Even worse…I met people who took a Vietnam sleeper train half way through its journey to discover their beds had been slept in just before they got on!!

Use the toilet early in the journey – The toilets weren’t unbearable when I boarded at Ninh Binh. However, by the time we arrived in Hue, they were hideous! I suggest using them as early as possible. Given the motion of the train, things spill out…

Take in the views – you’ll board the sleeper train in the dark, however when the sun rises, you’ll be treated to some pretty spectacular views!

I hope this helps anyone looking to make the journey from Tam Coc or Ninh Binh to Hue via a Vietnam sleeper train. Despite all the horror stories I had heard and read, it was a great journey. Very efficient, logistically easy, cheaper than flying and it saved me a night of accommodation. Other guides I have on travelling in Vietnam include, Vietnam Visas and the best time to travel to Vietnam.

Related Posts

hanoi travel guide

Exploring Hanoi: A Full Guide on the Best Things to Do

Hanoi, the capital of Vietnam, is a city where ancient traditions coexist with modern developments. Nestled along the banks of …
best things to do in hue

Best 6 Things to Do in Hue, Vietnam

Hue, the former imperial capital of Vietnam, is a city that resonates with historical significance and cultural richness. Found along …
hoi an old town

Exploring Hoi An, Vietnam

Hoi An, a charming town on Vietnam’s central coast, is a destination that seamlessly blends history, culture, and a relaxed …

The Best Things to do in Tam Coc, Ninh Binh

When people think of Vietnam, their minds usually go straight to the classic destinations; Hanoi, Ho Chi Minh City, Hoi …
Vietnam Visa

The Best Time to Visit Vietnam

Vietnam’s tropical monsoon climate brings diverse weather patterns across its three main regions, making the best travel time dependent on …

How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue

After an incredible 10 days in North Vietnam, it was time to start my journey down the country to Hue …

The post How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue appeared first on Char's Footsteps.

]]>
https://www.charsfootsteps.com/travel/asia/vietnam/ninh-binh-to-hue/feed/ 5
Vietnam Visa: How to Apply for a Vietnam Visa https://www.charsfootsteps.com/travel/asia/vietnam/vietnam-visa/?utm_source=rss&utm_medium=rss&utm_campaign=vietnam-visa https://www.charsfootsteps.com/travel/asia/vietnam/vietnam-visa/#comments Sat, 09 Jan 2021 19:00:51 +0000 https://www.charsfootsteps.com/?p=372 Vietnam is one of the most incredible countries I’ve had the opportunity to visit. I was lucky to spend a month there, travelling from North to South, back in 2019. In the lead up to my trip, I applied for an e-Visa 6 days before my flight and it wasn’t processed in time. Forcing me […]

The post Vietnam Visa: How to Apply for a Vietnam Visa appeared first on Char's Footsteps.

]]>
Vietnam is one of the most incredible countries I’ve had the opportunity to visit. I was lucky to spend a month there, travelling from North to South, back in 2019. In the lead up to my trip, I applied for an e-Visa 6 days before my flight and it wasn’t processed in time. Forcing me to apply for a separate Visa on Arrival and pay extra for urgent processing. The whole process was more complex than I had expected and motivated me to create this guide to help future travellers heading to Vietnam. Since then, there have been a lot of changes to the Vietnam Visas, therefore this blog has been updated to reflect the current visas. As always, be sure to double check with government websites to guarantee the latest advice.

hanoi travel guide

The Main Types of Vietnam Visa

There are several types of Visa options, depending on your intention to travel. Here are the main ones, but for the purpose of this blog, I’ll primarily be focusing on the tourist visas.

Tourist Visa (DL): The tourist visa is perfect for leisure travelers or tourists looking to explore Vietnam for a short period of time. There are single-entry options which are valid for 30 days, allowing one entry. Along with multiple-entry options, allowing unlimited entry for up to 90 days.

Business Visa (DN): The business visa is for those intending to visit Vietnam for work, business meetings or short-term employment. There are single and multiple entry options, with validity for 1-12 months depending on purpose and employer sponsorship.

Investor Visa (DT1-DT4): Ideal for individuals or company representatives with significant financial investments in Vietnam. These last up to 5 years and can be applied for with small investments, all the way up to VND100 billion.

Work Permit and Temporary Resident Visa (LĐ/TT): For employees with long-term work contracts with Vietnamese companies or international businesses operating in Vietnam. This is valid for 1-3 years.

Student Visa (DH): Foreign students enrolled in educational institutions in Vietnam. Validity is determined by course length but is usually up to 12 months.

Vietnam Visa Application Process

There are several ways to apply for a Vietnam Visa! This includes the E-Visa, Visa on Arrival and via the Embassy.

E-Visa Application

The E-Visa is probably the easiest and cheapest way to obtain a Vietnam Visa. Available to citizens in over 80 countries, the entire process is done online and is typically processed within 3 working days. It allows for both single and multiple entries and permits a stay of up to 90 days in Vietnam. Here is a link to the E-Visa application from the official government site. Alternatively you can apply for the E-Visa Application via third party agencies, and although this does cost more, can sometimes be a bit clearer/easier.

Vietnam e-Visa Requirements

  • A Passport which is valid for at least 6 months.
  • A clear, scanned copy of your full passport data page in .jpg format.
  • A passport-sized photo in .jpg format with a white background
  • Your entry and exit dates AND points of entry. You can enter and exit via air, land and sea. Check out this official list of every port you can use to enter and exit Vietnam from.
  • A valid credit or debit card for the e-visa payment fee.
  • A temporary address in Vietnam which can include a hotel, homestay, family address etc.

The application process is fairly straightforward. Upload all passport images and fill in any required information, before making the payment. After this, you’ll receive a registration codeSAVE THIS NUMBER!!! Once you’ve applied, it’ll take a few days before your visa is released.

To download your Vietnam e-Visa, you’ll need to enter your registration code, email and DoB to gain access to a pdf file. Print two copies of this – one for the border entry and one to keep with you during your travels as a just-in-case. Upon arrival in Vietnam, take your printed e-Visa and passport straight to immigration. You won’t need to follow signs to Visa on Arrival.

Visa on Arrival (VOA)

Unlike other countries, where VOA visas can be obtained upon arriving at border gates (e.g. Bali Visa on Arrival), Vietnam’s process is different. For this visa, travellers need to apply for a pre-approved visa letter via a travel or visa agency, in order to get the visa stamp upon arrival. The Vietnam Visa on Arrival (V.O.A) is for air travel only. This is a great option for emergency cases, as it’s possible to obtain this visa letter in just a few hours.

VOA Process

Find a visa agency and complete an online application for an approval letter. This can take 3-5 business days for standard processing and up to 8 hours for urgent processing.

Once you’ve received the approval letter via email, print a hard copy! Prepare 2 passport sized photos to be attached to this printed approval letter. Your passport must be valid for at least 6 months and you’ll need to prepare cash for the stamping fee at the airport. This is $25 USD for a single entry visa and $50 USD for multiple entry visa and they only accept cash!

Once you arrival at an international airport in Vietnam, follow signs for Visa on Arrival and hand over your passport and documents at the counter. Again, this is your passport, printed approval letter, 2 passport sized photos and stamping fee in USD cash.

There is typically a wait for this, in terms of queueing and processing time. I waited around 90 minutes for mine…not ideal after a long flight with layovers. When you’re called forward, pay your stamping fee, collect your passport (with your new Vietnam visa inside) and head to immigration.

Embassy or Consulate Application

The third way to obtain a Vietnam visa is via your nearest Vietnamese Embassy or consulate. To apply, visit your nearest Vietnamese embassy with: visa application form (fill this out ahead of time!), valid passport (with at least 6 months remaining), self-addressed envelope and the visa fee in your local currency. You’ll need other supporting documents if you’re applying for visas other than the tourist one.

The processing time varies, but it typically takes 5-7 working days. So be organised and apply well in advance to give yourself enough time. Fill documents out ahead of time and arrive early at the embassy to avoid queues. Once your forms are handed in, you’ll be sent to a payment counter.

Again, if you arrive into Vietnam via land or sea, you MUST have your visa already: via an embassy or e-Visa.

Vietnam Visa Exemptions

Some countries are exempt from needing a visa to enter Vietnam. As of 2024, there are now 25 countries that do not require a visa up to a period of time. You can find a detailed list of countries that are exempt from needing a visa to enter Vietnam here.

Note: A period of at least 30 days is required between two visa-free visits.

Tips on the Vietnam Visa Process

My biggest advice when applying for a Vietnam Visa;

Be organised and apply for your visa well in advance! You’ll need to note your date AND point of entry when applying – the visa will only be valid from this date. Getting it a bit in advance won’t hurt and will save any last minute stress.

Bring cash – I recommend brining cash in both Vietnamese Dong AND USD. When I arrived in Vietnam, the one ATM on our side of immigration was out of order. Luckily I had cash but other travellers were stuck and had to wait for security to bring them to another ATM in the airport. Not ideal after a long flight.

Hope this helps anyone looking to apply for a Vietnam visa! Enjoy your time in this beautiful country. I did a full trip from North to South, starting in Hanoi and ending in HCMC and loved every second of it! Other key areas I’d urge you to explore are Tam Coc and Hoi An! Read my guide on the best time to visit Vietnam for more information around planning a trip around the varying weather.

    Related Posts

    hanoi travel guide

    Exploring Hanoi: A Full Guide on the Best Things to Do

    Hanoi, the capital of Vietnam, is a city where ancient traditions coexist with modern developments. Nestled along the banks of …
    best things to do in hue

    Best 6 Things to Do in Hue, Vietnam

    Hue, the former imperial capital of Vietnam, is a city that resonates with historical significance and cultural richness. Found along …
    hoi an old town

    Exploring Hoi An, Vietnam

    Hoi An, a charming town on Vietnam’s central coast, is a destination that seamlessly blends history, culture, and a relaxed …

    The Best Things to do in Tam Coc, Ninh Binh

    When people think of Vietnam, their minds usually go straight to the classic destinations; Hanoi, Ho Chi Minh City, Hoi …
    Vietnam Visa

    The Best Time to Visit Vietnam

    Vietnam’s tropical monsoon climate brings diverse weather patterns across its three main regions, making the best travel time dependent on …

    How to Take the Sleeper Train from Tam Coc / Ninh Binh to Hue

    After an incredible 10 days in North Vietnam, it was time to start my journey down the country to Hue …

    The post Vietnam Visa: How to Apply for a Vietnam Visa appeared first on Char's Footsteps.

    ]]>
    https://www.charsfootsteps.com/travel/asia/vietnam/vietnam-visa/feed/ 9