New drop-menu for picking a standard bit size.
This commit is contained in:
@@ -1,91 +0,0 @@
|
||||
<script lang="ts">
|
||||
import TextField from "@smui/textfield";
|
||||
import Select, { Option } from "@smui/select";
|
||||
import type { MenuComponentDev } from "@smui/menu";
|
||||
import Menu from "@smui/menu";
|
||||
import List, { Item, Text } from "@smui/list";
|
||||
import { onMount } from "svelte";
|
||||
import { set_input_value } from "svelte/internal";
|
||||
|
||||
let menu: MenuComponentDev;
|
||||
|
||||
type Option = {
|
||||
value: number;
|
||||
label: string;
|
||||
metric: boolean;
|
||||
};
|
||||
|
||||
export let label: string;
|
||||
export let value: number;
|
||||
export let metric: boolean;
|
||||
export let options: Option[];
|
||||
|
||||
let textValue = "";
|
||||
|
||||
$: if (textValue) {
|
||||
value = Number.parseFloat(textValue) || null;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
textValue = value?.toString() || "";
|
||||
});
|
||||
|
||||
function onOptionSelected(option: Option) {
|
||||
textValue = option.value.toString();
|
||||
metric = option.metric;
|
||||
}
|
||||
|
||||
function filterKeys(event) {
|
||||
const input = event.target;
|
||||
|
||||
if (input.value.match(/[^0-9.]/)) {
|
||||
input.value = input.value.replace(/[^0-9.]/g, "");
|
||||
}
|
||||
|
||||
if (input.value.match(/\.[^.]*\./)) {
|
||||
input.value = input.value.replace(/(\.[^.]*)\./g, "$1");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="value-and-unit">
|
||||
<TextField
|
||||
{label}
|
||||
on:keypress={filterKeys}
|
||||
on:keyup={filterKeys}
|
||||
bind:value={textValue}
|
||||
on:click={() => menu.setOpen(true)}
|
||||
/>
|
||||
<Select bind:value={metric}>
|
||||
<Option value={true}>mm</Option>
|
||||
<Option value={false}>in</Option>
|
||||
</Select>
|
||||
</div>
|
||||
<Menu bind:this={menu} anchorCorner="BOTTOM_LEFT">
|
||||
<List>
|
||||
{#each options as option}
|
||||
<Item on:SMUI:action={() => onOptionSelected(option)}>
|
||||
<Text>{option.label}</Text>
|
||||
</Item>
|
||||
{/each}
|
||||
</List>
|
||||
</Menu>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
:global {
|
||||
.value-and-unit {
|
||||
display: flex;
|
||||
column-gap: 10px;
|
||||
|
||||
.mdc-select {
|
||||
max-width: 60px;
|
||||
}
|
||||
|
||||
.smui-select--standard .mdc-select__dropdown-icon {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import TextField from "@smui/textfield";
|
||||
import Icon from "@smui/textfield/icon";
|
||||
import HelperText from "@smui/textfield/helper-text";
|
||||
import MenuSurface, {
|
||||
type MenuSurfaceComponentDev,
|
||||
} from "@smui/menu-surface";
|
||||
import List, { Item, Text } from "@smui/list";
|
||||
import { virtualKeyboardChange } from "$lib/CustomActions";
|
||||
import { onDestroy } from "svelte";
|
||||
|
||||
let menuSurface: MenuSurfaceComponentDev;
|
||||
let menuTimeout;
|
||||
let optionSelected: boolean = false;
|
||||
|
||||
export let value: string;
|
||||
export let options: string[][];
|
||||
export let valid: boolean;
|
||||
export let helperText: string;
|
||||
|
||||
onDestroy(() => {
|
||||
if (menuTimeout) {
|
||||
clearTimeout(menuTimeout);
|
||||
menuTimeout = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
function showMenu(show: boolean) {
|
||||
if (show && optionSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
optionSelected = false;
|
||||
|
||||
if (menuTimeout) {
|
||||
clearTimeout(menuTimeout);
|
||||
}
|
||||
|
||||
// Use a timeout to "debounce" the display of the menu.
|
||||
menuTimeout = setTimeout(() => menuSurface.setOpen(show), 100);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="textfield-with-options">
|
||||
<TextField
|
||||
bind:value
|
||||
on:focusin={() => showMenu(true)}
|
||||
on:focusout={() => showMenu(false)}
|
||||
use={[[virtualKeyboardChange, (newValue) => (value = newValue)]]}
|
||||
{...$$restProps}
|
||||
>
|
||||
<div slot="trailingIcon">
|
||||
{#if valid}
|
||||
<Icon class="fa fa-check-circle-o" style="color: green;" />
|
||||
{/if}
|
||||
</div>
|
||||
<HelperText persistent slot="helper">{helperText}</HelperText>
|
||||
</TextField>
|
||||
|
||||
<MenuSurface bind:this={menuSurface} anchorCorner="BOTTOM_LEFT">
|
||||
<div style="display: flex; flex-direction: row;">
|
||||
{#each options as group}
|
||||
<List>
|
||||
{#each group as option}
|
||||
<Item
|
||||
on:SMUI:action={() => {
|
||||
value = option;
|
||||
showMenu(false);
|
||||
|
||||
optionSelected = true;
|
||||
}}
|
||||
>
|
||||
<Text>{option}</Text>
|
||||
</Item>
|
||||
{/each}
|
||||
</List>
|
||||
{/each}
|
||||
</div>
|
||||
</MenuSurface>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
:global {
|
||||
.textfield-with-options {
|
||||
.mdc-deprecated-list-item {
|
||||
height: 35px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@
|
||||
import TextField from "@smui/textfield";
|
||||
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
||||
import * as api from "$lib/api";
|
||||
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||
import { virtualKeyboardChange } from "$lib/CustomActions";
|
||||
|
||||
// https://man7.org/linux/man-pages/man7/hostname.7.html
|
||||
//
|
||||
@@ -73,7 +73,7 @@
|
||||
<Content id="change-hostname-dialog-content">
|
||||
<TextField
|
||||
bind:value={hostname}
|
||||
use={[[virtualKeyboardChangeHelper, (newValue) => (hostname = newValue)]]}
|
||||
use={[[virtualKeyboardChange, (newValue) => (hostname = newValue)]]}
|
||||
label="New Hostname"
|
||||
spellcheck="false"
|
||||
variant="filled"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import TextField from "@smui/textfield";
|
||||
import Button, { Label } from "@smui/button";
|
||||
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
||||
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||
import { virtualKeyboardChange } from "$lib/CustomActions";
|
||||
|
||||
export let open: boolean;
|
||||
export let axis = "";
|
||||
@@ -31,7 +31,7 @@
|
||||
label="Absolute"
|
||||
type="number"
|
||||
bind:value
|
||||
use={[[virtualKeyboardChangeHelper, (newValue) => (value = newValue)]]}
|
||||
use={[[virtualKeyboardChange, (newValue) => (value = newValue)]]}
|
||||
variant="filled"
|
||||
style="width: 100%;"
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script type="ts">
|
||||
import DimensionInput from "$components/DimensionInput.svelte";
|
||||
import Dialog, { Title, Content, Actions } from "@smui/dialog";
|
||||
import Button, { Label } from "@smui/button";
|
||||
import { waitForChange } from "$lib/StoreHelpers";
|
||||
@@ -13,14 +12,23 @@
|
||||
probingFailed,
|
||||
probingStarted,
|
||||
} from "$lib/ControllerState";
|
||||
import { numberWithUnit } from "$lib/RegexHelpers";
|
||||
import TextFieldWithOptions from "$components/TextFieldWithOptions.svelte";
|
||||
|
||||
type Step =
|
||||
| "None"
|
||||
| "CheckProbe"
|
||||
| "BitDimensions"
|
||||
| "PlaceProbeBlock"
|
||||
| "Probe"
|
||||
| "Done";
|
||||
const ValidSteps = [
|
||||
"None",
|
||||
"CheckProbe",
|
||||
"BitDimensions",
|
||||
"PlaceProbeBlock",
|
||||
"Probe",
|
||||
"Done",
|
||||
] as const;
|
||||
|
||||
type Step = typeof ValidSteps[number];
|
||||
|
||||
function isStep(str): str is Step {
|
||||
return ValidSteps.includes(str);
|
||||
}
|
||||
|
||||
const stepLabels: Record<Step, string> = {
|
||||
None: "",
|
||||
@@ -34,21 +42,16 @@
|
||||
const cancelled = writable(false);
|
||||
const userAcknowledged = writable(false);
|
||||
|
||||
const cutterDiameterOptions = [
|
||||
{ value: 0.5, label: '1/2 "', metric: false },
|
||||
{ value: 0.25, label: '1/4 "', metric: false },
|
||||
{ value: 0.125, label: '1/8 "', metric: false },
|
||||
{ value: 10, label: "10 mm", metric: true },
|
||||
{ value: 6, label: "6 mm", metric: true },
|
||||
{ value: 3, label: "10 mm", metric: true },
|
||||
];
|
||||
const imperialBits = ["1/2 in", "1/4 in", "1/8 in"];
|
||||
const metricBits = ["10 mm", "8 mm", "6 mm", "3 mm"];
|
||||
|
||||
export let open;
|
||||
export let probeType: "xyz" | "z";
|
||||
let currentStep: Step = "None";
|
||||
let cutterDiameter: number;
|
||||
let cutterDiameterString: string = "";
|
||||
let cutterDiameterMetric: number;
|
||||
let showCancelButton = true;
|
||||
let steps: Array<Step> = [];
|
||||
let steps: Step[] = [];
|
||||
let nextButton = {
|
||||
label: "Next",
|
||||
disabled: false,
|
||||
@@ -56,10 +59,12 @@
|
||||
};
|
||||
|
||||
$: metric = $Config.settings?.units === "METRIC";
|
||||
$: cutterDiameterMetric = numberWithUnit
|
||||
.parse(cutterDiameterString)
|
||||
?.toMetric();
|
||||
|
||||
$: if (open) {
|
||||
cutterDiameter =
|
||||
Number.parseFloat(localStorage.getItem("cutterDiameter")) || null;
|
||||
cutterDiameterString = localStorage.getItem("cutterDiameter") ?? "";
|
||||
|
||||
// Svelte appears not to like it when you invoke
|
||||
// an async function from a reactive statement, so we
|
||||
@@ -67,32 +72,31 @@
|
||||
requestAnimationFrame(begin);
|
||||
}
|
||||
|
||||
$: if (cutterDiameter) {
|
||||
$: if (cutterDiameterString) {
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
function removeSkippedSteps(steps: Step[]): Step[] {
|
||||
return steps.filter((x) => x);
|
||||
}
|
||||
|
||||
async function begin() {
|
||||
try {
|
||||
$probingActive = true;
|
||||
assertValidProbeType();
|
||||
|
||||
steps = removeSkippedSteps([
|
||||
steps = [
|
||||
"CheckProbe",
|
||||
probeType === "xyz" ? "BitDimensions" : undefined,
|
||||
"PlaceProbeBlock",
|
||||
"Probe",
|
||||
"Done",
|
||||
]);
|
||||
].filter<Step>(isStep);
|
||||
|
||||
await stepCompleted("CheckProbe", probeContacted);
|
||||
|
||||
if (probeType === "xyz") {
|
||||
await stepCompleted("BitDimensions", userAcknowledged);
|
||||
localStorage.setItem("cutterDiameter", cutterDiameter.toString());
|
||||
localStorage.setItem(
|
||||
"cutterDiameter",
|
||||
numberWithUnit.normalize(cutterDiameterString)
|
||||
);
|
||||
}
|
||||
|
||||
await stepCompleted("PlaceProbeBlock", userAcknowledged);
|
||||
@@ -177,11 +181,7 @@
|
||||
break;
|
||||
|
||||
case "BitDimensions":
|
||||
nextButton.disabled = !(
|
||||
cutterDiameter !== null &&
|
||||
cutterDiameter !== 0 &&
|
||||
isFinite(cutterDiameter)
|
||||
);
|
||||
nextButton.disabled = !isFinite(cutterDiameterMetric);
|
||||
break;
|
||||
|
||||
case "Done":
|
||||
@@ -204,8 +204,8 @@
|
||||
|
||||
const cutterLength = 12.7;
|
||||
const zLift = 1;
|
||||
const xOffset = probeBlockWidth + cutterDiameter / 2.0;
|
||||
const yOffset = probeBlockLength + cutterDiameter / 2.0;
|
||||
const xOffset = probeBlockWidth + cutterDiameterMetric / 2.0;
|
||||
const yOffset = probeBlockLength + cutterDiameterMetric / 2.0;
|
||||
const zOffset = probeBlockHeight;
|
||||
|
||||
if (probeType === "z") {
|
||||
@@ -269,11 +269,11 @@
|
||||
scrimClickAction=""
|
||||
aria-labelledby="probe-dialog-title"
|
||||
aria-describedby="probe-dialog-content"
|
||||
surface$style="width: 700px; height: 400px; max-width: calc(100vw - 32px); overflow: visible;"
|
||||
surface$style="width: 700px; max-width: calc(100vw - 32px);"
|
||||
>
|
||||
<Title id="probe-dialog-title">Probing {probeType?.toUpperCase()}</Title>
|
||||
|
||||
<Content id="probe-dialog-content" style="overflow: visible;">
|
||||
<Content id="probe-dialog-content">
|
||||
<div class="steps">
|
||||
<p><b>Step {steps.indexOf(currentStep) + 1} of {steps.length}</b></p>
|
||||
<ul>
|
||||
@@ -282,48 +282,49 @@
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="current-step">
|
||||
<p>
|
||||
{#if currentStep === "CheckProbe"}
|
||||
Attach the probe magnet to the collet, then touch the probe block to
|
||||
the bit.
|
||||
{:else if currentStep === "BitDimensions"}
|
||||
<DimensionInput
|
||||
label="Cutter diameter"
|
||||
options={cutterDiameterOptions}
|
||||
bind:value={cutterDiameter}
|
||||
{metric}
|
||||
/>
|
||||
{:else if currentStep === "PlaceProbeBlock"}
|
||||
<p>
|
||||
{#if currentStep === "CheckProbe"}
|
||||
Attach the probe magnet to the collet, then touch the probe block to the
|
||||
bit.
|
||||
{:else if currentStep === "BitDimensions"}
|
||||
<TextFieldWithOptions
|
||||
label="Cutter diameter"
|
||||
variant="filled"
|
||||
spellcheck="false"
|
||||
style="width: 100%;"
|
||||
bind:value={cutterDiameterString}
|
||||
options={[imperialBits, metricBits]}
|
||||
valid={isFinite(cutterDiameterMetric)}
|
||||
helperText={`Examples: 1/2", 10 mm, 0.25 in`}
|
||||
/>
|
||||
{:else if currentStep === "PlaceProbeBlock"}
|
||||
{#if probeType === "xyz"}
|
||||
Place the probe block face up, on the lower-left corner of your
|
||||
workpiece.
|
||||
{:else}
|
||||
Place the probe block face down, with the bit above the recess.
|
||||
{/if}
|
||||
{:else if currentStep === "Probe"}
|
||||
Probing in progress...
|
||||
{:else if currentStep === "Done"}
|
||||
{#if $probingFailed}
|
||||
Could not find the probe block during probing!
|
||||
|
||||
<p>
|
||||
Make sure the tip of the bit is less than {metric ? "25mm" : "1 in"}
|
||||
above the probe block, and try again.
|
||||
</p>
|
||||
{:else}
|
||||
Don't forget to put away the probe!
|
||||
|
||||
{#if probeType === "xyz"}
|
||||
Place the probe block face up, on the lower-left corner of your
|
||||
workpiece.
|
||||
{:else}
|
||||
Place the probe block face down, with the bit above the recess.
|
||||
{/if}
|
||||
{:else if currentStep === "Probe"}
|
||||
Probing in progress...
|
||||
{:else if currentStep === "Done"}
|
||||
{#if $probingFailed}
|
||||
Could not find the probe block during probing!
|
||||
<p>The machine will now move to the XY origin.</p>
|
||||
|
||||
<p>
|
||||
Make sure the tip of the bit is less than {metric
|
||||
? "25mm"
|
||||
: "1 in"} above the probe block, and try again.
|
||||
</p>
|
||||
{:else}
|
||||
Don't forget to put away the probe!
|
||||
|
||||
{#if probeType === "xyz"}
|
||||
<p>The machine will now move to the XY origin.</p>
|
||||
|
||||
<p>Watch your hands!</p>
|
||||
{/if}
|
||||
<p>Watch your hands!</p>
|
||||
{/if}
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</p>
|
||||
</Content>
|
||||
|
||||
<Actions>
|
||||
@@ -358,12 +359,9 @@
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.current-step {
|
||||
flex-grow: 1;
|
||||
|
||||
.mdc-text-field {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.bit-dimensions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.steps {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import TextField from "@smui/textfield";
|
||||
import Button, { Label } from "@smui/button";
|
||||
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
||||
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||
import { virtualKeyboardChange } from "$lib/CustomActions";
|
||||
|
||||
export let open: boolean;
|
||||
export let axis = "";
|
||||
@@ -43,7 +43,7 @@
|
||||
label="Position"
|
||||
type="number"
|
||||
bind:value
|
||||
use={[[virtualKeyboardChangeHelper, (newValue) => (value = newValue)]]}
|
||||
use={[[virtualKeyboardChange, (newValue) => (value = newValue)]]}
|
||||
spellcheck="false"
|
||||
variant="filled"
|
||||
style="width: 100%;"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import CircularProgress from "@smui/circular-progress";
|
||||
import VirtualList from "svelte-tiny-virtual-list";
|
||||
import * as api from "$lib/api";
|
||||
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||
import { virtualKeyboardChange } from "$lib/CustomActions";
|
||||
|
||||
const itemHeight = 35;
|
||||
|
||||
@@ -154,9 +154,7 @@
|
||||
<Label>Date & Time</Label>
|
||||
<TextField
|
||||
bind:value
|
||||
use={[
|
||||
[virtualKeyboardChangeHelper, (newValue) => (value = newValue)],
|
||||
]}
|
||||
use={[[virtualKeyboardChange, (newValue) => (value = newValue)]]}
|
||||
label="Time"
|
||||
type="datetime-local"
|
||||
variant="filled"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
||||
import type { WifiNetwork } from "$lib/NetworkInfo";
|
||||
import * as api from "$lib/api";
|
||||
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||
import { virtualKeyboardChange } from "$lib/CustomActions";
|
||||
|
||||
export let open = false;
|
||||
export let network: WifiNetwork;
|
||||
@@ -57,7 +57,7 @@
|
||||
{#if needPassword}
|
||||
<TextField
|
||||
bind:value={password}
|
||||
use={[[virtualKeyboardChangeHelper, (newValue) => (password = newValue)]]}
|
||||
use={[[virtualKeyboardChange, (newValue) => (password = newValue)]]}
|
||||
label="Password"
|
||||
spellcheck="false"
|
||||
variant="filled"
|
||||
|
||||
9
src/svelte-components/src/lib/CustomActions.ts
Normal file
9
src/svelte-components/src/lib/CustomActions.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export function virtualKeyboardChange(node: HTMLElement, cb: (value: any) => void) {
|
||||
const input = node.querySelector("input");
|
||||
if (!input) {
|
||||
console.error("Could not find the textfield's <input>:", node);
|
||||
throw new Error("Could not find the textfield's <input>");
|
||||
}
|
||||
|
||||
input.addEventListener("keyup", () => cb(input.value));
|
||||
}
|
||||
90
src/svelte-components/src/lib/RegexHelpers.ts
Normal file
90
src/svelte-components/src/lib/RegexHelpers.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
type NumberWithUnit = {
|
||||
value: number,
|
||||
metric: boolean,
|
||||
toMetric: () => number;
|
||||
}
|
||||
|
||||
function numberWithUnitToMetric() {
|
||||
return this.metric ? this.value : this.value * 25.4;
|
||||
}
|
||||
|
||||
function isPojo(value) {
|
||||
if (value === null || typeof value !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Object.getPrototypeOf(value) === Object.prototype;
|
||||
}
|
||||
|
||||
const fractions = [
|
||||
{ value: 0.75, formatted: "3/4" },
|
||||
{ value: 0.625, formatted: "5/8" },
|
||||
{ value: 0.5, formatted: "1/2" },
|
||||
{ value: 0.375, formatted: "3/8" },
|
||||
{ value: 0.25, formatted: "1/4" },
|
||||
{ value: 0.1875, formatted: "3/16" },
|
||||
{ value: 0.125, formatted: "1/8" },
|
||||
{ value: 0.09375, formatted: "3/32" },
|
||||
{ value: 0.0625, formatted: "1/16" },
|
||||
{ value: 0.03125, formatted: "1/32" },
|
||||
];
|
||||
|
||||
function formatFraction(value: number) {
|
||||
const fraction = fractions.find(f => f.value === value);
|
||||
|
||||
return fraction ? fraction.formatted : value.toString();
|
||||
}
|
||||
|
||||
export const numberWithUnit = {
|
||||
regex: /^\s*(?:(\d+)\s*\/\s*(\d+)|(\d*\.\d+)|(\d+(?:\.\d+)?))\s*("|in|inch|inches|mm|millimeters)\s*$/,
|
||||
parse: function (str: string) {
|
||||
let [, numerator, denominator, decimal1, decimal2, unit]: any = str?.match(numberWithUnit.regex) ?? [];
|
||||
|
||||
numerator = Number.parseFloat(numerator)
|
||||
denominator = Number.parseFloat(denominator)
|
||||
decimal1 = Number.parseFloat(decimal1)
|
||||
decimal2 = Number.parseFloat(decimal2)
|
||||
|
||||
const metric = (unit ?? "").includes("m");
|
||||
|
||||
switch (true) {
|
||||
case isFinite(numerator) && isFinite(denominator):
|
||||
return {
|
||||
value: numerator / denominator,
|
||||
metric,
|
||||
toMetric: numberWithUnitToMetric
|
||||
};
|
||||
|
||||
case isFinite(decimal1) && decimal1 !== 0:
|
||||
return {
|
||||
value: decimal1,
|
||||
metric,
|
||||
toMetric: numberWithUnitToMetric
|
||||
};
|
||||
|
||||
case isFinite(decimal2) && decimal2 !== 0:
|
||||
return {
|
||||
value: decimal2,
|
||||
metric,
|
||||
toMetric: numberWithUnitToMetric
|
||||
};
|
||||
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
normalize: function (str) {
|
||||
const value = this.parse(str);
|
||||
|
||||
switch (true) {
|
||||
case !isPojo(value):
|
||||
return "";
|
||||
|
||||
case value.metric:
|
||||
return `${value.value} mm`
|
||||
|
||||
default:
|
||||
return `${formatFraction(value.value)} in`
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export function virtualKeyboardChangeHelper(node: HTMLElement, cb: (value: any) => void) {
|
||||
const input = node.querySelector("input");
|
||||
input.addEventListener("keyup", () => cb(input.value));
|
||||
}
|
||||
@@ -15,7 +15,6 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
build: {
|
||||
minify: false,
|
||||
target: "chrome60",
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'src/main.ts'),
|
||||
|
||||
Reference in New Issue
Block a user