Skip to content

Commit

Permalink
Merge pull request #124 from samply/feature/date-picker-component
Browse files Browse the repository at this point in the history
feat(date picker): add date picker component
  • Loading branch information
MatsJohansen87 authored Sep 6, 2024
2 parents bd931f2 + a5c614b commit d9fd9c9
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 108 deletions.
54 changes: 5 additions & 49 deletions packages/lib/src/components/catalogue/DataTreeElement.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import AutocompleteComponent from "./AutoCompleteComponent.svelte";
import SingleSelectComponent from "./SingleSelectComponent.svelte";
import { v4 as uuidv4 } from "uuid";
import { activeNumberInputs, openTreeNodes } from "../../stores/catalogue";
import { openTreeNodes } from "../../stores/catalogue";
import type { QueryItem } from "../../types/queryData";
import { iconStore } from "../../stores/icons";
import InfoButtonComponent from "../buttons/InfoButtonComponent.wc.svelte";
import DatePickerComponent from "./DatePickerComponent.svelte";
export let element: Category;
const subCategoryName: string | null =
Expand Down Expand Up @@ -100,45 +101,6 @@
typeof element.fieldType === "string" &&
element.fieldType == "single-select"));
/**
* watches the number input store to update the number input components
*/
$: numberInput = $activeNumberInputs.find(
(item) => item.key === element.key,
);
/**
* adds the number input to the store if it is not already in the store
* @param store
* @returns updated store
*/
activeNumberInputs.update((store: QueryItem[]): QueryItem[] => {
if (
"fieldType" in element &&
element.fieldType === "number" &&
!store.find((item) => item.key === element.key)
) {
return [
...store,
{
id: uuidv4(),
key: element.key,
name: element.name,
system: "system" in element ? element.system : "",
type: "type" in element ? element.type : "",
values: [
{
name: "0",
value: { min: 0, max: 0 },
queryBindId: uuidv4(),
},
],
},
];
}
return store;
});
$: selectAllText = $iconStore.get("selectAllText");
const selectAllOptions = (): void => {
Expand Down Expand Up @@ -219,15 +181,9 @@
{:else if "fieldType" in element && element.fieldType === "autocomplete"}
<AutocompleteComponent {element} />
{:else if "fieldType" in element && element.fieldType === "number"}
{#each numberInput.values as numberInputValues (numberInputValues.queryBindId)}
<NumberInputComponent
{element}
queryItem={{
...numberInput,
values: [numberInputValues],
}}
/>
{/each}
<NumberInputComponent {element} />
{:else if "fieldType" in element && element.fieldType === "date"}
<DatePickerComponent {element} />
{/if}
</div>
{/if}
Expand Down
94 changes: 94 additions & 0 deletions packages/lib/src/components/catalogue/DatePickerComponent.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<script lang="ts">
import type { Category } from "../../types/treeData";
import { catalogueTextStore } from "../../stores/texts";
import QueryAddButtonComponent from "./QueryAddButtonComponent.svelte";
import type { QueryItem } from "../../types/queryData";
import { v4 as uuidv4 } from "uuid";
export let element: Category;
let from: string = element.min || "1900-01-01";
let to: string = element.max || new Date().toISOString().split("T")[0];
/**
* build the proper name for the query value
* @returns the "from", "≥ from", "≤ to", "from - to" or "invalid"
*/
const transformName = (): string => {
if (from === to) return `${from}`;
if (!to && from) return `≥ ${from}`;
if (!from && to) return `≤ ${to}`;
if (from < to) return ` ${from} - ${to}`;
return "invalid";
};
/**
* builds the query item each time the values change
*/
let queryItem: QueryItem;
$: queryItem = {
id: uuidv4(),
key: element.key,
name: element.name,
type: "type" in element && element.type,
values: [
{
name: transformName(),
value: { min: from, max: to },
queryBindId: uuidv4(),
},
],
};
/**
* when the fields loose focus, the values are reset to the starting values
*/
const handleInputFrom = (): void => {
if (from === null || from === "" || from === undefined) {
from = element.min || new Date().toISOString().split("T")[0];
}
};
const handleInputTo = (): void => {
if (to === null || to === "" || to === undefined) {
to = element.max || new Date().toISOString().split("T")[0];
}
};
</script>

<div part="criterion-wrapper date-input-wrapper">
<div part="criterion-item">
<div part="criterion-section criterion-section-values">
<label
part="date-input-label date-input-values-label lens-date-input-values-label-from"
>
{$catalogueTextStore.numberInput.labelFrom}
<input
part="date-input-formfield date-input-formfield-from {to &&
from > to
? ' formfield-error'
: ''}"
type="date"
bind:value={from}
on:focusout={handleInputFrom}
/>
</label>

<label
part="date-input-label date-input-values-label lens-date-input-values-label-to"
>
{$catalogueTextStore.numberInput.labelTo}
<input
part="date-input-formfield date-input-formfield-to{to &&
from > to
? ' formfield-error'
: ''}"
type="date"
bind:value={to}
on:focusout={handleInputTo}
/>
</label>
</div>
<QueryAddButtonComponent {queryItem} />
</div>
</div>
63 changes: 10 additions & 53 deletions packages/lib/src/components/catalogue/NumberInputComponent.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
<script lang="ts">
import { queryStore } from "../../stores/query";
import type { QueryItem, QueryValue } from "../../types/queryData";
import { catalogueTextStore } from "../../stores/texts";
import QueryAddButtonComponent from "./QueryAddButtonComponent.svelte";
import { activeNumberInputs } from "../../stores/catalogue";
import type { Category } from "../../types/treeData";
import { v4 as uuidv4 } from "uuid";
export let queryItem: QueryItem;
export let element: Category;
const queryBindId = queryItem.values[0].queryBindId;
const value = queryItem.values[0].value as { min: number; max: number };
let from: number | null = value.min;
let to: number | null = value.max;
let from: number | null = element.min || 0;
let to: number | null = element.max || 0;
/**
* handles the "from" input field
Expand Down Expand Up @@ -74,55 +68,18 @@
};
/**
* update all groups in the query store when from or to changes
* update values in the activeNumberInputs store
* @param from
* @param to
*/
const updateStores = (from: number, to: number): void => {
queryStore.update((store: QueryItem[][]): QueryItem[][] => {
store.forEach((queryGroup: QueryItem[]) => {
queryGroup.forEach((item: QueryItem) => {
item.values.forEach((queryValue: QueryValue) => {
if (queryValue.queryBindId === queryBindId) {
queryValue.name = transformName();
queryValue.value = { min: from, max: to };
}
});
});
});
return store;
});
activeNumberInputs.update((store: QueryItem[]): QueryItem[] => {
store.forEach((item: QueryItem) => {
if (item.key === queryItem.key) {
item.values.forEach((queryValue: QueryValue) => {
if (queryValue.queryBindId === queryBindId) {
queryValue.name = transformName();
queryValue.value = { min: from, max: to };
}
});
}
});
return store;
});
};
$: updateStores(from, to);
/**
* when some parts of the element change, the values are watched
* and the QuerySelectComponent is passed thoes new values
* build the query item each time the values change
*/
$: queryItem = {
...queryItem,
id: uuidv4(),
key: element.key,
name: element.name,
type: "type" in element && element.type,
values: [
{
name: transformName(),
value: { min: from, max: to },
queryBindId: queryBindId,
queryBindId: uuidv4(),
},
],
};
Expand All @@ -149,7 +106,7 @@
>
{$catalogueTextStore.numberInput.labelTo}
<input
part="number-input-formfield number-input-formfield-from
part="number-input-formfield number-input-formfield-to
{to && from > to ? ' formfield-error' : ''}"
type="number"
bind:value={to}
Expand Down
3 changes: 0 additions & 3 deletions packages/lib/src/stores/catalogue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { writable } from "svelte/store";
import type { Category, TreeNode } from "../types/treeData";
import type { QueryItem } from "../types/queryData";

/**
* store to hold the catalogue
Expand All @@ -14,8 +13,6 @@ export const openTreeNodes = writable<
Map<string, { key: string; subCategoryNames: string[] | null }>
>(new Map());

export const activeNumberInputs = writable<QueryItem[]>([]);

/**
* get the bottom level items of a category
* @param category string of the category you want to get the bottom level items from
Expand Down
43 changes: 41 additions & 2 deletions packages/lib/src/styles/catalogue.css
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,6 @@ lens-catalogue::part(criterion-section-values) {
/**
* Number Input
*/


lens-catalogue::part(criterion-item-number-input) {
display: grid;
grid-template-columns: 1fr auto 1fr;
Expand All @@ -197,6 +195,12 @@ lens-catalogue::part(number-input-formfield) {
font-size: var(--font-size-s);
}

lens-catalogue::part(number-input-formfield)::-webkit-inner-spin-button,
lens-catalogue::part(number-input-formfield)::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}

lens-catalogue::part(number-input-formfield):focus {
border-color: var(--blue);
outline: none;
Expand All @@ -206,6 +210,41 @@ lens-catalogue::part(number-input-add) {
margin-top: var(--gap-s);
}


/**
* Date Picker
*/
lens-catalogue::part(criterion-item-date-input) {
display: grid;
grid-template-columns: 1fr auto 1fr;
}

lens-catalogue::part(date-input-label) {
display: flex;
align-items: center;
}

lens-catalogue::part(date-input-formfield) {
font-family: var(--font-family);
width: 120px;
margin-left: var(--gap-xs);
border: solid 1px var(--dark-gray);
border-top: none;
border-radius: var(--border-radius-small);
text-align: center;
font-size: var(--font-size-s);
}

lens-catalogue::part(date-input-formfield):focus {
border-color: var(--blue);
outline: none;
}

lens-catalogue::part(date-input-add) {
margin-top: var(--gap-s);
}


/**
* Autocomplete
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/lib/src/types/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ export type AstBottomLayerValue = {
| boolean
| Array<string>
| { min: number; max: number }
| { min: Date | undefined; max: Date | undefined };
| { min: string; max: string }; // for dates
};

0 comments on commit d9fd9c9

Please sign in to comment.