♻️ Refactor bundle mechanism

Mainly leave shadow-cljs for build cljs stuff and use esbuild
for bundle all js dependencies, completly avoiding all possible
incompatibility issues between js libraries and google closure
compiler.
This commit is contained in:
Andrey Antukh 2024-10-31 16:43:20 +01:00
parent 366bca5f93
commit 607deb31dc
45 changed files with 2833 additions and 257 deletions

View file

@ -6,7 +6,7 @@
(ns app.main.data.events
(:require
["ua-parser-js" :as UAParser]
["ua-parser-js" :as ua]
[app.common.data :as d]
[app.common.logging :as l]
[app.config :as cf]
@ -38,7 +38,7 @@
(defn- collect-context
[]
(let [uagent (UAParser.)]
(let [uagent (new ua/UAParser)]
(merge
{:app-version (:full cf/version)
:locale @i18n/locale}

View file

@ -7,7 +7,7 @@
(ns app.main.data.shortcuts
(:refer-clojure :exclude [meta reset!])
(:require
["./shortcuts_impl.js$default" :as mousetrap]
["@penpot/mousetrap$default" :as mousetrap]
[app.common.data.macros :as dm]
[app.common.logging :as log]
[app.common.schema :as sm]

View file

@ -1,48 +0,0 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) KALEIDOS INC
*/
"use strict";
import Mousetrap from 'mousetrap'
if (Mousetrap.addKeycodes) {
Mousetrap.addKeycodes({
219: '219'
});
}
const target = Mousetrap.prototype || Mousetrap;
target.stopCallback = function (e, element, combo) {
// if the element has the data attribute "mousetrap-dont-stop" then no need
// to stop. It should be used like <div data-mousetrap-dont-stop>...</div>
// or :div {:data-mousetrap-dont-stop true}
if ('mousetrapDontStop' in element.dataset) {
return false
}
if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) {
return false;
}
if ('composedPath' in e && typeof e.composedPath === 'function') {
// For open shadow trees, update `element` so that the following check works.
const initialEventTarget = e.composedPath()[0];
if (initialEventTarget !== e.target) {
element = initialEventTarget;
}
}
// stop for input, select, textarea and button
const shouldStop = element.tagName == "INPUT" ||
element.tagName == "SELECT" ||
element.tagName == "TEXTAREA" ||
(element.tagName == "BUTTON" && combo.includes("tab")) ||
(element.contentEditable && element.contentEditable == "true");
return shouldStop;
}
export default Mousetrap;

View file

@ -6,7 +6,7 @@
(ns app.main.data.workspace.media
(:require
["svgo" :as svgo]
["@penpot/svgo$default" :as svgo]
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]

View file

@ -6,7 +6,7 @@
(ns app.main.data.workspace.texts
(:require
["penpot/vendor/text-editor-v2" :as editor.v2]
["@penpot/text-editor" :as editor.v2]
[app.common.attrs :as attrs]
[app.common.data :as d]
[app.common.data.macros :as dm]

View file

@ -280,7 +280,7 @@
(fn [event]
(st/emit! (dd/hide-file-menu))
(when can-edit
(let [offset (dom/get-offset-position (.-nativeEvent event))
(let [offset (dom/get-offset-position (dom/event->native-event event))
select-current? (not (contains? selected-files (:id file)))

View file

@ -15,6 +15,7 @@
[app.main.render :as render]
[app.main.store :as st]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.object :as obj]
[app.util.timers :as ts]
@ -46,9 +47,10 @@
on-scroll
(fn [event]
(if (pos? (.. event -nativeEvent -deltaY))
(on-right-arrow-click event)
(on-left-arrow-click event)))
(let [event (dom/event->native-event event)]
(if (pos? (.-deltaY ^js event))
(on-right-arrow-click event)
(on-left-arrow-click event))))
on-mount
(fn []

View file

@ -16,6 +16,7 @@
[app.main.ui.hooks :as h]
[app.main.ui.icons :as i]
[app.util.color :as uc]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
@ -92,7 +93,9 @@
(mf/use-callback
(mf/deps max-offset)
(fn [event]
(let [delta (+ (.. event -nativeEvent -deltaY) (.. event -nativeEvent -deltaX))]
(let [event (dom/event->native-event event)
delta (+ (.. ^js event -deltaY)
(.. ^js event -deltaX))]
(if (pos? delta)
(on-right-arrow-click event)
(on-left-arrow-click event)))))]

View file

@ -61,8 +61,8 @@
nil)))
(defn- styles-fn [shape styles content]
(let [data (if (= (.getText content) "")
(-> (.getData content)
(let [data (if (= (.getText ^js content) "")
(-> ^js (.getData content)
(.toJS)
(js->clj :keywordize-keys true))
(txt/styles-to-attrs styles))]

View file

@ -134,8 +134,8 @@
(let [children (-> (array/normalize-to-array children)
(array/without-nils))
is-button? #(= :title-button (.. % -props -role))
is-content? #(= :content (.. % -props -role))
is-button? #(as-> % $ (= :title-button (.. ^js $ -props -role)))
is-content? #(as-> % $ (= :content (.. ^js $ -props -role)))
buttons (array/filter is-button? children)
content (array/filter is-content? children)
@ -222,7 +222,8 @@
(defn set-drag-image
[event item-ref num-selected]
(let [offset (dom/get-offset-position (.-nativeEvent event))
(let [offset (dom/get-offset-position
(dom/event->native-event event))
item-el (mf/ref-val item-ref)
counter-el (create-counter-element num-selected)]

View file

@ -14,6 +14,7 @@
[app.main.store :as st]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[app.util.object :as obj]
[cuerdas.core :as str]
@ -111,7 +112,9 @@
(mf/use-callback
(mf/deps max-offset)
(fn [event]
(let [delta (+ (.. event -nativeEvent -deltaY) (.. event -nativeEvent -deltaX))]
(let [event (dom/event->native-event event)
delta (+ (.. ^js event -deltaY)
(.. ^js event -deltaX))]
(if (pos? delta)
(on-right-arrow-click event)
(on-left-arrow-click event)))))]

View file

@ -65,15 +65,15 @@
(dom/stop-propagation bevent)
(when-not @z?
(let [event (.-nativeEvent bevent)
(let [event (dom/event->native-event bevent)
ctrl? (kbd/ctrl? event)
meta? (kbd/meta? event)
shift? (kbd/shift? event)
alt? (kbd/alt? event)
mod? (kbd/mod? event)
left-click? (and (not panning) (= 1 (.-which event)))
middle-click? (and (not panning) (= 2 (.-which event)))]
left-click? (and (not panning) (dom/left-mouse? bevent))
middle-click? (and (not panning) (dom/middle-mouse? bevent))]
(cond
(or middle-click? (and left-click? @space?))
@ -120,12 +120,11 @@
(mf/use-callback
(mf/deps @hover @hover-ids selected @space? @z? read-only?)
(fn [bevent]
(let [event (.-nativeEvent bevent)
(let [event (dom/event->native-event bevent)
shift? (kbd/shift? event)
mod? (kbd/mod? event)
left-click? (= 1 (.-which event))]
mod? (kbd/mod? event)]
(when (and left-click?
(when (and (dom/left-mouse? bevent)
(not mod?)
(not shift?)
(not @space?))
@ -275,7 +274,7 @@
;; Release pointer on mouse up
(.releasePointerCapture target (.-pointerId event)))
(let [event (.-nativeEvent event)
(let [event (dom/event->native-event event)
ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event)
alt? (kbd/alt? event)
@ -475,7 +474,7 @@
(assoc :y final-y)))))
(dnd/has-type? event "penpot/component")
(let [event (.-nativeEvent event)
(let [event (dom/event->native-event event)
ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event)
alt? (kbd/alt? event)

View file

@ -959,9 +959,8 @@
handle-pointer-down
(mf/use-fn
(fn [event]
(let [left-click? (= 1 (.-which (.-nativeEvent event)))]
(when left-click?
(dom/stop-propagation event)))))
(when (dom/left-mouse? event)
(dom/stop-propagation event))))
handle-add-column
(mf/use-fn

View file

@ -110,7 +110,7 @@
(mf/use-fn
(mf/deps frame workspace-read-only?)
(fn [bevent]
(let [event (.-nativeEvent bevent)
(let [event (dom/event->native-event bevent)
position (dom/get-client-position event)]
(dom/prevent-default event)
(dom/stop-propagation event)

View file

@ -6,7 +6,7 @@
(ns app.util.code-highlight
(:require
["highlight.js" :as hljs]
["@penpot/hljs" :as hljs]
[app.util.dom :as dom]))
(defn highlight!

View file

@ -756,10 +756,17 @@
(trigger-download-uri filename mtype uri)))
(defn left-mouse? [bevent]
(let [event (.-nativeEvent ^js bevent)]
(defn left-mouse?
[bevent]
(let [event (.-nativeEvent ^js bevent)]
(= 1 (.-which event))))
(defn middle-mouse?
[bevent]
(let [event (.-nativeEvent ^js bevent)]
(= 2 (.-which event))))
;; Warning: need to protect against reverse tabnabbing attack
;; https://www.comparitech.com/blog/information-security/reverse-tabnabbing/
(defn open-new-window

View file

@ -7,8 +7,7 @@
(ns app.util.text-editor
"Draft related abstraction functions."
(:require
["./text_editor_impl.js" :as impl]
["draft-js" :as draft]
["@penpot/draft-js" :as impl]
[app.common.text :as txt]))
;; --- CONVERSION
@ -34,12 +33,12 @@
(defn import-content
[content]
(-> content txt/convert-to-draft clj->js draft/convertFromRaw))
(-> content txt/convert-to-draft clj->js impl/convertFromRaw))
(defn export-content
[content]
(-> content
(draft/convertToRaw)
(impl/convertToRaw)
(js->clj :keywordize-keys true)
(txt/convert-from-draft)))

View file

@ -1,408 +0,0 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) KALEIDOS INC
*/
'use strict';
import {
BlockMapBuilder,
CharacterMetadata,
CompositeDecorator,
EditorState,
Modifier,
RichTextEditorUtil,
SelectionState,
} from "draft-js";
import DraftPasteProcessor from 'draft-js/lib/DraftPasteProcessor';
import {Map, OrderedSet} from "immutable";
function isDefined(v) {
return v !== undefined && v !== null;
}
function mergeBlockData(block, newData) {
let data = block.getData();
for (let key of Object.keys(newData)) {
const oldVal = data.get(key);
if (oldVal === newData[key]) {
data = data.delete(key);
} else {
data = data.set(key, newData[key]);
}
}
return block.mergeDeep({
data: data
});
}
export function createEditorState(content, decorator) {
if (content === null) {
return EditorState.createEmpty(decorator);
} else {
return EditorState.createWithContent(content, decorator);
}
}
export function createDecorator(type, component) {
const strategy = (block, callback, content) => {
return block.findEntityRanges((cmeta) => {
const entityKey = cmeta.getEntity();
return isDefined(entityKey) && (type === content.getEntity(entityKey).getType());
}, callback);
};
return new CompositeDecorator([
{"strategy": strategy, "component": component}
]);
}
function getSelectAllSelection(state) {
const content = state.getCurrentContent();
const firstBlock = content.getBlockMap().first();
const lastBlock = content.getBlockMap().last();
return new SelectionState({
"anchorKey": firstBlock.getKey(),
"anchorOffset": 0,
"focusKey": lastBlock.getKey(),
"focusOffset": lastBlock.getLength()
});
}
function getCursorInEndPosition(state) {
const content = state.getCurrentContent();
const lastBlock = content.getBlockMap().last();
return new SelectionState({
"anchorKey": lastBlock.getKey(),
"anchorOffset": lastBlock.getLength(),
"focusKey": lastBlock.getKey(),
"focusOffset": lastBlock.getLength()
});
}
export function selectAll(state) {
return EditorState.forceSelection(state, getSelectAllSelection(state));
}
function modifySelectedBlocks(contentState, selectionState, operation) {
var startKey = selectionState.getStartKey();
var endKey = selectionState.getEndKey();
var blockMap = contentState.getBlockMap();
var newBlocks = blockMap.toSeq().skipUntil(function (_, k) {
return k === startKey;
}).takeUntil(function (_, k) {
return k === endKey;
}).concat(Map([[endKey, blockMap.get(endKey)]])).map(operation);
return contentState.merge({
"blockMap": blockMap.merge(newBlocks),
"selectionBefore": selectionState,
"selectionAfter": selectionState
});
}
export function updateCurrentBlockData(state, attrs) {
const selection = state.getSelection();
let content = state.getCurrentContent();
content = modifySelectedBlocks(content, selection, (block) => {
return mergeBlockData(block, attrs);
});
return EditorState.push(state, content, "change-block-data");
}
function addStylesToOverride(styles, other) {
let result = styles;
for (let style of other) {
const [p, k, v] = style.split("$$$");
const prefix = [p, k, ""].join("$$$");
const curValue = result.find((it) => it.startsWith(prefix))
if (curValue) {
result = result.remove(curValue);
}
result = result.add(style);
}
return result
}
export function applyInlineStyle(state, styles) {
const userSelection = state.getSelection();
let selection = userSelection;
let result = state;
if (selection.isCollapsed()) {
const currentOverride = state.getCurrentInlineStyle() || new OrderedSet();
const styleOverride = addStylesToOverride(currentOverride, styles)
return EditorState.setInlineStyleOverride(state, styleOverride);
}
let content = null;
for (let style of styles) {
const [p, k, v] = style.split("$$$");
const prefix = [p, k, ""].join("$$$");
content = result.getCurrentContent();
content = removeInlineStylePrefix(content, selection, prefix);
if (v !== "z:null") {
content = Modifier.applyInlineStyle(content, selection, style);
}
result = EditorState.push(result, content, "change-inline-style");
}
return EditorState.acceptSelection(result, userSelection);
}
export function splitBlockPreservingData(state) {
let content = state.getCurrentContent();
const selection = state.getSelection();
content = Modifier.splitBlock(content, selection);
const blockData = content.blockMap.get(content.selectionBefore.getStartKey()).getData();
const blockKey = content.selectionAfter.getStartKey();
const blockMap = content.blockMap.update(blockKey, (block) => {
return block.set("data", blockData);
});
content = content.set("blockMap", blockMap);
return EditorState.push(state, content, "split-block");
}
export function addBlurSelectionEntity(state) {
let content = state.getCurrentContent(state);
const selection = state.getSelection();
content = content.createEntity("PENPOT_SELECTION", "MUTABLE");
const entityKey = content.getLastCreatedEntityKey();
content = Modifier.applyEntity(content, selection, entityKey);
return EditorState.push(state, content, "apply-entity");
}
export function removeBlurSelectionEntity(state) {
const selectionAll = getSelectAllSelection(state);
const selection = state.getSelection();
let content = state.getCurrentContent();
content = Modifier.applyEntity(content, selectionAll, null);
state = EditorState.push(state, content, "apply-entity");
state = EditorState.forceSelection(state, selection);
return state;
}
export function getCurrentBlock(state) {
const content = state.getCurrentContent();
const selection = state.getSelection();
const startKey = selection.getStartKey();
return content.getBlockForKey(startKey);
}
export function getCurrentEntityKey(state) {
const block = getCurrentBlock(state);
const selection = state.getSelection();
const startOffset = selection.getStartOffset();
return block.getEntityAt(startOffset);
}
export function removeInlineStylePrefix(contentState, selectionState, stylePrefix) {
const startKey = selectionState.getStartKey();
const startOffset = selectionState.getStartOffset();
const endKey = selectionState.getEndKey();
const endOffset = selectionState.getEndOffset();
return modifySelectedBlocks(contentState, selectionState, (block, blockKey) => {
let sliceStart;
let sliceEnd;
if (startKey === endKey) {
sliceStart = startOffset;
sliceEnd = endOffset;
} else {
sliceStart = blockKey === startKey ? startOffset : 0;
sliceEnd = blockKey === endKey ? endOffset : block.getLength();
}
let chars = block.getCharacterList();
let current;
while (sliceStart < sliceEnd) {
current = chars.get(sliceStart);
current = current.set("style", current.getStyle().filter((s) => !s.startsWith(stylePrefix)))
chars = chars.set(sliceStart, CharacterMetadata.create(current));
sliceStart++;
}
return block.set("characterList", chars);
});
}
export function cursorToEnd(state) {
const newSelection = getCursorInEndPosition(state);
const selection = state.getSelection();
let content = state.getCurrentContent();
content = Modifier.applyEntity(content, newSelection, null);
state = EditorState.forceSelection(state, newSelection);
state = EditorState.push(state, content, "apply-entity");
return state;
}
export function isCurrentEmpty(state) {
const selection = state.getSelection();
if (!selection.isCollapsed()) {
return false;
}
const blockKey = selection.getStartKey();
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block.getText() === "";
}
/*
Returns the block keys between a selection
*/
export function getSelectedBlocks(state) {
const selection = state.getSelection();
const startKey = selection.getStartKey();
const endKey = selection.getEndKey();
const content = state.getCurrentContent();
const result = [ startKey ];
let currentKey = startKey;
while (currentKey !== endKey) {
const currentBlock = content.getBlockAfter(currentKey);
currentKey = currentBlock.getKey();
result.push(currentKey);
}
return result;
}
export function getBlockContent(state, blockKey) {
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block.getText();
}
export function getBlockData(state, blockKey) {
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block && block.getData().toJS();
}
export function updateBlockData(state, blockKey, data) {
const userSelection = state.getSelection();
const inlineStyleOverride = state.getInlineStyleOverride();
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
const newBlock = mergeBlockData(block, data);
const blockData = newBlock.getData();
const newContent = Modifier.setBlockData(
state.getCurrentContent(),
SelectionState.createEmpty(blockKey),
blockData
);
let result = EditorState.push(state, newContent, 'change-block-data');
result = EditorState.acceptSelection(result, userSelection);
result = EditorState.setInlineStyleOverride(result, inlineStyleOverride);
return result;
}
export function getSelection(state) {
return state.getSelection();
}
export function setSelection(state, selection) {
return EditorState.acceptSelection(state, selection);
}
export function selectBlock(state, blockKey) {
const block = state.getCurrentContent().getBlockForKey(blockKey);
const length = block.getText().length;
const selection = SelectionState.createEmpty(blockKey).merge({
focusOffset: length
});
return EditorState.acceptSelection(state, selection);
}
export function getInlineStyle(state, blockKey, offset) {
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block.getInlineStyleAt(offset).toJS();
}
const NEWLINE_REGEX = /\r\n?|\n/g;
function splitTextIntoTextBlocks(text) {
return text.split(NEWLINE_REGEX);
}
export function insertText(state, text, attrs, inlineStyles) {
const blocks = splitTextIntoTextBlocks(text);
const character = CharacterMetadata.create({style: OrderedSet(inlineStyles)});
let blockArray = DraftPasteProcessor.processText(
blocks,
character,
"unstyled",
);
blockArray = blockArray.map((b) => {
return mergeBlockData(b, attrs);
});
const fragment = BlockMapBuilder.createFromArray(blockArray);
const content = state.getCurrentContent();
const selection = state.getSelection();
const newContent = Modifier.replaceWithFragment(
content,
selection,
fragment
);
const resultSelection = SelectionState.createEmpty(selection.getStartKey());
return EditorState.push(state, newContent, 'insert-fragment');
}
export function setInlineStyleOverride(state, inlineStyles) {
return EditorState.setInlineStyleOverride(state, inlineStyles);
}
export function selectionEquals(selection, other) {
return selection.getAnchorKey() === other.getAnchorKey() &&
selection.getAnchorOffset() === other.getAnchorOffset() &&
selection.getFocusKey() === other.getFocusKey() &&
selection.getFocusOffset() === other.getFocusOffset() &&
selection.getIsBackward() === other.getIsBackward();
}

View file

@ -6,7 +6,36 @@
(ns app.util.time
(:require
["./time_impl" :as impl]
["date-fns/format$default" :as dfn-format]
["date-fns/formatDistanceToNowStrict$default" :as dfn-distance-to-now]
["date-fns/locale/ar-SA$default" :as dfn-ar]
["date-fns/locale/ca$default" :as dfn-ca]
["date-fns/locale/cs$default" :as dfn-cs]
["date-fns/locale/de$default" :as dfn-de]
["date-fns/locale/el$default" :as dfn-el]
["date-fns/locale/en-US$default" :as df-en-us]
["date-fns/locale/es$default" :as dfn-es]
["date-fns/locale/eu$default" :as dfn-eu]
["date-fns/locale/fa-IR$default" :as dfn-fa-ir]
["date-fns/locale/fr$default" :as dfn-fr]
["date-fns/locale/gl$default" :as dfn-gl]
["date-fns/locale/he$default" :as dfn-he]
["date-fns/locale/hr$default" :as dfn-hr]
["date-fns/locale/id$default" :as dfn-id]
["date-fns/locale/it$default" :as dfn-it]
["date-fns/locale/ja$default" :as dfn-ja]
["date-fns/locale/ko$default" :as dfn-ko]
["date-fns/locale/lv$default" :as dfn-lv]
["date-fns/locale/nb$default" :as dfn-nb]
["date-fns/locale/nl$default" :as dfn-nl]
["date-fns/locale/pl$default" :as dfn-pl]
["date-fns/locale/pt$default" :as dfn-pt]
["date-fns/locale/pt-BR$default" :as dfn-pt-br]
["date-fns/locale/ro$default" :as dfn-ro]
["date-fns/locale/ru$default" :as dfn-ru]
["date-fns/locale/tr$default" :as dfn-tr]
["date-fns/locale/uk$default" :as dfn-uk]
["date-fns/locale/zh-CN$default" :as dfn-zh-cn]
[app.common.data.macros :as dm]
[app.common.time :as common-time]
[app.util.object :as obj]
@ -15,6 +44,42 @@
(dm/export common-time/DateTime)
(dm/export common-time/Duration)
(def locales
#js {:ar dfn-ar
:ca dfn-ca
:de dfn-de
:el dfn-el
:en df-en-us
:en_us df-en-us
:es dfn-es
:es_es dfn-es
:fa dfn-fa-ir
:fa_ir dfn-fa-ir
:fr dfn-fr
:he dfn-he
:pt dfn-pt
:pt_pt dfn-pt
:pt_br dfn-pt-br
:ro dfn-ro
:ru dfn-ru
:tr dfn-tr
:zh-cn dfn-zh-cn
:nl dfn-nl
:eu dfn-eu
:gl dfn-gl
:hr dfn-hr
:it dfn-it
:nb dfn-nb
:nb_no dfn-nb
:pl dfn-pl
:id dfn-id
:uk dfn-uk
:cs dfn-cs
:lv dfn-lv
:ko dfn-ko
:ja dfn-ja
:ja_jp dfn-ja})
(defprotocol ITimeMath
(plus [_ o])
(minus [_ o]))
@ -199,18 +264,18 @@
(let [v (if (datetime? v) (format v :date) v)]
(->> #js {:includeSeconds true
:addSuffix true
:locale (obj/get impl/locales locale)}
(impl/format-distance-to-now v))))))
:locale (obj/get locales locale)}
(dfn-distance-to-now v))))))
(defn format-date-locale
([v] (format-date-locale v nil))
([v {:keys [locale] :or {locale "en"}}]
(when v
(let [v (if (datetime? v) (format v :date) v)
locale (obj/get impl/locales locale)
locale (obj/get locales locale)
f (.date (.-formatLong ^js locale) v)]
(->> #js {:locale locale}
(impl/format v f))))))
(dfn-format v f))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Measurement Helpers

View file

@ -1,71 +0,0 @@
import {format as dfnFormat} from "date-fns/format";
import {formatDistanceToNowStrict as dfnFormatDistance} from "date-fns/formatDistanceToNowStrict";
import {arSA} from "date-fns/locale/ar-SA";
import {ca} from "date-fns/locale/ca";
import {de} from "date-fns/locale/de";
import {el} from "date-fns/locale/el";
import {enUS} from "date-fns/locale/en-US";
import {es} from "date-fns/locale/es";
import {faIR} from "date-fns/locale/fa-IR";
import {fr} from "date-fns/locale/fr";
import {he} from "date-fns/locale/he";
import {pt} from "date-fns/locale/pt";
import {ptBR} from "date-fns/locale/pt-BR";
import {ro} from "date-fns/locale/ro";
import {ru} from "date-fns/locale/ru";
import {tr} from "date-fns/locale/tr";
import {zhCN} from "date-fns/locale/zh-CN";
import {nl} from "date-fns/locale/nl";
import {eu} from "date-fns/locale/eu";
import {gl} from "date-fns/locale/gl";
import {hr} from "date-fns/locale/hr";
import {it} from "date-fns/locale/it";
import {nb} from "date-fns/locale/nb";
import {pl} from "date-fns/locale/pl";
import {id} from "date-fns/locale/id";
import {uk} from "date-fns/locale/uk";
import {cs} from "date-fns/locale/cs";
import {lv} from "date-fns/locale/lv";
import {ko} from "date-fns/locale/ko";
import {ja} from "date-fns/locale/ja";
export const locales = {
"ar": arSA,
"ca": ca,
"de": de,
"el": el,
"en": enUS,
"en_us": enUS,
"es": es,
"es_es": es,
"fa": faIR,
"fa_ir": faIR,
"fr": fr,
"he": he,
"pt": pt,
"pt_pt": pt,
"pt_br": ptBR,
"ro": ro,
"ru": ru,
"tr": tr,
"zh_cn": zhCN,
"nl": nl,
"eu": eu,
"gl": gl,
"hr": hr,
"it": it,
"nb": nb,
"nb_no": nb,
"pl": pl,
"id": id,
"uk": uk,
"cs": cs,
"lv": lv,
"ko": ko,
"ja": ja,
"ja_jp": ja,
};
export const format = dfnFormat;
export const format_distance_to_now = dfnFormatDistance;