Skip to content

Commit

Permalink
Merge pull request #1379 from Wizleap-Inc/feat/number-input
Browse files Browse the repository at this point in the history
feat: number-input
  • Loading branch information
ichi-h authored Oct 7, 2024
2 parents 52c7c6c + 16fde5d commit b942063
Show file tree
Hide file tree
Showing 12 changed files with 464 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .changeset/chilly-lobsters-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@wizleap-inc/wiz-ui-react": minor
"@wizleap-inc/wiz-ui-next": minor
"@wizleap-inc/wiz-ui-constants": minor
"@wizleap-inc/wiz-ui-styles": minor
---

Feat: WizNumberInput
1 change: 1 addition & 0 deletions packages/constants/component/name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const ComponentName = {
ChatCard: "WizChatCard",
ChatForm: "WizChatForm",
ChatItem: "WizChatItem",
NumberInput: "WizNumberInput",
Notification: "WizNotification",
NotificationList: "WizNotificationList",
NotificationPanel: "WizNotificationPanel",
Expand Down
87 changes: 87 additions & 0 deletions packages/styles/bases/number-input.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { style } from "@vanilla-extract/css";
import { THEME } from "@wizleap-inc/wiz-ui-constants";

import { fontSizeStyle } from "../commons";

export const container = style({
position: "relative",
background: THEME.color.white["800"],
borderRadius: THEME.spacing.xs2,
boxSizing: "border-box",
overflow: "hidden",
});

export const disabled = style({
backgroundColor: THEME.color.gray[300],
cursor: "not-allowed",
});

export const input = style({
"::-webkit-outer-spin-button": {
appearance: "none",
margin: 0,
},
"::-webkit-inner-spin-button": {
appearance: "none",
margin: 0,
},
MozAppearance: "textfield",
textAlign: "right",
minWidth: "30%",
border: "none",
outline: "none",
padding: `${THEME.spacing.xs2} ${THEME.spacing.xs}`,
lineHeight: THEME.fontSize.xl,
flexGrow: 1,
fontSize: THEME.fontSize.sm,
color: THEME.color.gray["800"],
"::placeholder": {
color: THEME.color.gray["500"],
userSelect: "none",
},
":disabled": {
cursor: "not-allowed",
backgroundColor: THEME.color.gray["300"],
color: THEME.color.gray["500"],
},
});

export const button = style({
lineHeight: 0.2,
position: "relative",
cursor: "pointer",
padding: THEME.spacing.xs2,
borderRadius: THEME.spacing.no,
boxSizing: "border-box",
borderColor: THEME.color.gray["400"],
border: "none",
borderLeft: `1px solid ${THEME.color.gray["400"]}`,
background: "transparent",
fill: THEME.color.gray["500"],
selectors: {
"&:hover:not(:disabled)": {
"@media": {
"(any-hover: hover)": {
backgroundColor: THEME.color.green["300"],
fill: THEME.color.green["800"],
},
},
},
"&:active:not(:disabled)": {
backgroundColor: THEME.color.green["800"],
fill: THEME.color.white["800"],
},
},
":disabled": {
cursor: "not-allowed",
},
});

export const arrowIcon = style([
fontSizeStyle.xs2,
{
transform: "scale(2)",
pointerEvents: "none",
color: "currentcolor",
},
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as WizNumberInput } from "./number-input.vue";
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Meta, StoryFn } from "@storybook/vue3";

import { WizHStack } from "@/components";

import { WizNumberInput } from ".";

export default {
title: "Base/Input/NumberInput",
component: WizNumberInput,
} as Meta<typeof WizNumberInput>;

const Template: StoryFn<typeof WizNumberInput> = (args) => ({
components: { WizNumberInput, WizHStack },
setup() {
return { args };
},
template: `
<div>
<WizNumberInput v-bind="args" v-model="args.modelValue"/>
<div> value : {{ args.modelValue }} </div>
</div>
`,
});
export const Default = Template.bind({});
Default.args = {};

export const Placeholder = Template.bind({});
Placeholder.args = {
placeholder: "数字を入力",
};

export const WithValue = Template.bind({});
WithValue.args = {
modelValue: 100,
};

export const Disabled = Template.bind({});
Disabled.args = {
modelValue: 100,
disabled: true,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<template>
<div
:class="[
styles.container,
disabled && styles.disabled,
inputBorderStyle[isError ? 'error' : hasFocus ? 'active' : 'default'],
]"
:style="{ display: 'flex', width: width }"
@focusin="hasFocus = true"
@focusout="hasFocus = false"
>
<input
:class="styles.input"
type="number"
:value="inputValue"
ref="inputRef"
@input="onInput"
v-bind="restProps"
:disabled="disabled"
/>
<WizVStack>
<button
type="button"
@click="handleStepUp"
:class="styles.button"
:disabled="disabled"
>
<WizIArrowDropUp :class="[styles.arrowIcon]" />
</button>
<WizDivider />
<button
type="button"
@click="handleStepDown"
:class="styles.button"
:disabled="disabled"
>
<WizIArrowDropDown :class="[styles.arrowIcon]" />
</button>
</WizVStack>
</div>
</template>

<script setup lang="ts" generic="T = number">
import { ComponentName } from "@wizleap-inc/wiz-ui-constants";
import * as styles from "@wizleap-inc/wiz-ui-styles/bases/number-input.css";
import { inputBorderStyle } from "@wizleap-inc/wiz-ui-styles/commons";
import { computed, inject, ref } from "vue";
import {
WizDivider,
WizIArrowDropDown,
WizIArrowDropUp,
WizVStack,
} from "@/components";
import { formControlKey } from "@/hooks/use-form-control-provider";
defineOptions({
name: ComponentName.NumberInput,
});
type Props = {
modelValue?: number;
placeholder?: string;
disabled?: boolean;
width?: string;
error?: boolean;
min?: number;
max?: number;
step?: number;
precision?: number;
};
const props = withDefaults(defineProps<Props>(), {
width: "7rem",
});
const emit = defineEmits(["update:modelValue"]);
const form = inject(formControlKey);
const isError = computed(() => (form ? form.isError.value : false));
const hasFocus = ref(false);
const inputRef = ref<HTMLInputElement | null>(null);
const inputValue = computed({
get() {
return props.modelValue !== null ? props.modelValue : "";
},
set(value) {
emit("update:modelValue", value !== "" ? Number(value) : null);
},
});
const triggerChangeEvent = () => {
if (inputRef.value) {
const event = new Event("input", { bubbles: true });
inputRef.value.dispatchEvent(event);
}
};
const handleStepUp = () => {
if (inputRef.value) {
inputRef.value.stepUp();
triggerChangeEvent();
}
};
const handleStepDown = () => {
if (inputRef.value) {
inputRef.value.stepDown();
triggerChangeEvent();
}
};
const onInput = (event: Event) => {
const target = event.target as HTMLInputElement;
const value = target.value;
emit("update:modelValue", value !== "" ? Number(value) : null);
};
const restProps = computed(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { modelValue, width, ...rest } = props;
return rest;
});
const disabled = computed(() => props.disabled);
const width = computed(() => props.width);
</script>
13 changes: 13 additions & 0 deletions packages/wiz-ui-next/src/components/custom/form/group.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
DateRange,
DateRangePickerSelectBoxOption,
} from "@/components/base/inputs/date-range-picker/types";
import { WizNumberInput } from "@/components/base/inputs/number-input";
import { RadioOption } from "@/components/base/inputs/radio/types";
import { SelectBoxOption } from "@/components/base/inputs/selectbox/types";

Expand Down Expand Up @@ -211,6 +212,7 @@ export const AllInput: StoryFn<typeof WizFormControl> = () => ({
WizDatePicker,
WizTimePicker,
WizDateRangePicker,
WizNumberInput,
},
setup() {
const textInput = ref("");
Expand Down Expand Up @@ -256,6 +258,7 @@ export const AllInput: StoryFn<typeof WizFormControl> = () => ({
{ label: "選択肢3", value: "3" },
]);
const selectBoxInput = ref("");
const numberInput = ref<number>();
return {
textInput,
passwordInput,
Expand All @@ -271,6 +274,7 @@ export const AllInput: StoryFn<typeof WizFormControl> = () => ({
dateRangeInput,
selectBoxOptions,
selectBoxInput,
numberInput,
};
},
template: `
Expand Down Expand Up @@ -302,6 +306,9 @@ export const AllInput: StoryFn<typeof WizFormControl> = () => ({
<WizFormControl label="WizDateRangePicker">
<WizDateRangePicker v-model="dateRangeInput" name="dateRangeInput" :selectBoxOptions="selectBoxOptions" v-model:selectBoxValue="selectBoxInput" />
</WizFormControl>
<WizFormControl label="WizNumberInput">
<WizNumberInput v-model="numberInput" name="numberInput" />
</WizFormControl>
</WizFormGroup>
`,
});
Expand All @@ -319,6 +326,7 @@ export const AllInputError: StoryFn<typeof WizFormControl> = () => ({
WizDatePicker,
WizTimePicker,
WizDateRangePicker,
WizNumberInput,
},
setup() {
const textInput = ref("");
Expand Down Expand Up @@ -364,6 +372,7 @@ export const AllInputError: StoryFn<typeof WizFormControl> = () => ({
{ label: "選択肢3", value: "3" },
]);
const selectBoxInput = ref("");
const numberInput = ref<number>();
return {
textInput,
passwordInput,
Expand All @@ -379,6 +388,7 @@ export const AllInputError: StoryFn<typeof WizFormControl> = () => ({
dateRangeInput,
selectBoxOptions,
selectBoxInput,
numberInput,
};
},
template: `
Expand Down Expand Up @@ -410,6 +420,9 @@ export const AllInputError: StoryFn<typeof WizFormControl> = () => ({
<WizFormControl label="WizDateRangePicker" error="エラーが発生しました">
<WizDateRangePicker v-model="dateRangeInput" name="dateRangeInput" :selectBoxOptions="selectBoxOptions" v-model:selectBoxValue="selectBoxInput" />
</WizFormControl>
<WizFormControl label="WizNumberInput" error="エラーが発生しました">
<WizNumberInput v-model="numberInput" name="numberInput" />
</WizFormControl>
</WizFormGroup>
`,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { WizNumberInput } from "./number-input";
Loading

0 comments on commit b942063

Please sign in to comment.