Skip to content

Commit

Permalink
feat(Demo): function values select (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
ValentinNelu authored Sep 29, 2023
1 parent 6321bfa commit 6ce8cf4
Show file tree
Hide file tree
Showing 16 changed files with 159 additions and 88 deletions.
5 changes: 3 additions & 2 deletions angular/demo/src/app/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {Provider} from '@angular/core';
import {InjectionToken, effect, inject} from '@angular/core';
import {toSignal} from '@angular/core/rxjs-interop';
import {ActivatedRoute} from '@angular/router';
import {getPropValues} from '@agnos-ui/common/propsValues';

function getJsonHash(json: string) {
const {config = {}, props = {}} = JSON.parse(json ?? '{}');
Expand All @@ -27,7 +28,7 @@ export function provideHashConfig(widgetName: keyof WidgetsConfig): Provider[] {
},
},
provideWidgetsConfig((parentConfig) => {
parentConfig[widgetName] = inject(hashConfigToken)().config;
parentConfig[widgetName] = getPropValues(inject(hashConfigToken)().config);
return parentConfig;
}),
];
Expand All @@ -46,7 +47,7 @@ export function hashChangeHook(propsCallback: (props: any) => void) {
}

effect(() => {
callPropsCallback(hashConfig$().props);
callPropsCallback(getPropValues(hashConfig$().props));
});
}

Expand Down
1 change: 1 addition & 0 deletions angular/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"paths": {
"@agnos-ui/core": ["./core/lib"],
"@agnos-ui/angular": ["./angular/lib/src/public-api"],
"@agnos-ui/common/*": ["./common/*"],
"@agnos-ui/angular-headless": ["./angular/headless/src/public-api"]
}
},
Expand Down
46 changes: 46 additions & 0 deletions common/propsValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {collapseVerticalTransition, fadeTransition} from '../core/lib/transitions/bootstrap';
import {getPaginationDefaultConfig, getRatingDefaultConfig} from '@agnos-ui/core';

export type PropsValues = keyof typeof propsValuesList;

const propsValuesList = {
//common
log: {value: (x: any) => console.log(x), label: 'Log'},
noop: {value: () => {}, label: 'Noop'},
//transitions
collapse: {value: collapseVerticalTransition, label: 'Collapse'},
fade: {value: fadeTransition, label: 'Fade'},
//rating
ratingValueFunction: {value: getRatingDefaultConfig().ariaValueTextFn, label: 'RatingValue'},
heartsRatingValue: {
value: (rating: number, maxRating: number) =>
`${rating} ${rating === 1 ? 'heart' : 'hearts'} out of ${maxRating} ${maxRating === 1 ? 'heart' : 'hearts'}`,
label: 'HeartsRatingValue',
},
starRatingValue: {
value: (rating: number, maxRating: number) =>
`${rating} ${rating === 1 ? 'star' : 'stars'} out of ${maxRating} ${maxRating === 1 ? 'star' : 'stars'}`,
label: 'StarRatingValue',
},
starIconRating: {value: getRatingDefaultConfig().slotStar, label: 'StarIconRating'},
heartIconRating: {value: ({fill}: {fill: number}) => String.fromCharCode(fill === 100 ? 9829 : 9825), label: 'HeartIconRating'},
//pagination
defaultPageFactory: {value: getPaginationDefaultConfig().pagesFactory, label: 'DefaultPageFactory'},
simpleLabel: {value: getPaginationDefaultConfig().ariaPageLabel, label: 'SimpleLabel'},
pageLabel: {value: (processPage: number, pageCount: number) => `Page ${processPage} of ${pageCount}`, label: 'PageLabel'},
slotNumberLabel: {value: getPaginationDefaultConfig().slotNumberLabel, label: 'SlotNumberLabel'},
};

export const getPropValues = (config: Record<string, any>) => {
const configUpdated = {...config};
for (const [key, value] of Object.entries(configUpdated)) {
if (propsValuesList[value?.value as PropsValues] !== undefined) {
configUpdated[key] = propsValuesList[value.value as PropsValues].value;
}
}
return configUpdated;
};

export const getPropValueLabel = (key: PropsValues) => {
return propsValuesList[key as PropsValues].label;
};
2 changes: 1 addition & 1 deletion common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function undefinedIfEmpty(object: object | undefined) {

/**
* Update the hash url
* @param type Type of value to be update
* @param type Type of value to be updated
* @param key
* @param value any value, or undefined to remove the key
*/
Expand Down
2 changes: 1 addition & 1 deletion demo/src/lib/layout/ComponentPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@

<Header title={componentName} {tabs} tab={$selectedTabName$} />
<div class="main-content">
<slot tab={$selectedTabName$} />
<slot />
</div>
5 changes: 3 additions & 2 deletions demo/src/lib/layout/playground/Playground.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
import PlaygroundLine from './PlaygroundLine.svelte';
import {createPlayground} from './playground';
import type {SampleInfo} from '../sample';
import type {PropsValues} from '@agnos-ui/common/propsValues';
export let sample: SampleInfo;
export let config: Record<string, any>;
export let doc: WidgetDoc;
export let types: Record<string, string> = {};
export let height = 100;
export let noresize = false;
const {values$, sampleParameters$, help$} = createPlayground({config, types, doc});
export let listPropsValues: Record<string, PropsValues[]> = {};
const {values$, sampleParameters$, help$} = createPlayground({config, types, doc, listPropsValues});
</script>

<div class="row">
Expand Down
2 changes: 0 additions & 2 deletions demo/src/lib/layout/playground/PlaygroundLine.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import {getPlaygroundContext} from './playground';
export let valueContext: ValueContextApi;
$: ({key, defaultValue, config, prop, type} = valueContext);
const {showHelp} = getPlaygroundContext();
</script>

Expand Down
92 changes: 29 additions & 63 deletions demo/src/lib/layout/playground/PlaygroundValue.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
import clearIcon from 'bootstrap-icons/icons/x-circle-fill.svg?raw';
import type {SingleValueContextApi} from './playground';
import Svg from '../Svg.svelte';
import {getPropValueLabel} from '@agnos-ui/common/propsValues';
export let type: string;
export let defaultValue: any;
export let api: SingleValueContextApi;
export let placeholder = '';
export let ariaLabel: string;
let value: string | undefined = api.selectValue;
$: valueOrDefault = api.isEmpty ? defaultValue : api.value;
</script>

{#if type === 'boolean'}
<td class="value">
<td class="value">
{#if type === 'boolean'}
<div class="form-check form-switch me-1">
<input
class="form-check-input boolean"
Expand All @@ -25,78 +27,42 @@
aria-label={ariaLabel}
/>
</div>
</td>
<td class="checkbox"
><button class="btn btn-link icon" title="Clear value" disabled={api.isEmpty} on:click={api.clear}
><Svg className="icon-20" svg={clearIcon} /></button
></td
{:else if type === 'number'}
<input class="number form-control" class:empty={api.isEmpty} {placeholder} value={api.value} on:input={api.onChange} aria-label={ariaLabel} />
{:else if type === 'function' && api.selectValues}
<select class="form-select function" class:empty={api.isEmpty} bind:value on:change={api.onChange} aria-label={ariaLabel}>
<option hidden disabled value={undefined} selected />
{#each api.selectValues as option}
<option value={option}>{getPropValueLabel(option)}</option>
{/each}
</select>
{:else}
<input class="form-control" class:empty={api.isEmpty} {placeholder} value={api.value} on:input={api.onChange} aria-label={ariaLabel} />
{/if}
</td>
<td class="checkbox align-middle">
<button
class="btn btn-link m-0 p-0 d-flex mx-auto"
title="Clear value"
disabled={api.isEmpty}
on:click={() => {
value = undefined;
api.clear();
}}
>
{:else if type === 'number'}
<td class="value">
<input class="number" class:empty={api.isEmpty} {placeholder} value={api.value} on:input={api.onChange} aria-label={ariaLabel} />
</td>
<td class="checkbox"
><button class="btn btn-link icon" title="Clear value" disabled={api.isEmpty} on:click={api.clear}
><Svg className="icon-20" svg={clearIcon} /></button
></td
>
{:else if type === 'function'}
<td class="value">
(function)
<!-- <select class="form-select function" class:empty={api.isEmpty} bind:value on:change={api.onChange}>
{#each computedOptions as option}
<option value={option}>{option}</option>
{/each}
</select> -->
</td>
<td class="checkbox"
><!-- <button class="btn btn-link icon" title="Clear value" disabled={api.isEmpty} on:click={api.clear}><Svg className="icon-20" svg={clearIcon} /> --></td
>
{:else}
<td class="value"
><input class="string" class:empty={api.isEmpty} {placeholder} value={api.value} on:input={api.onChange} aria-label={ariaLabel} /></td
>
<td class="checkbox"
><button class="btn btn-link icon" title="Clear value" disabled={api.isEmpty} on:click={api.clear}
><Svg className="icon-20" svg={clearIcon} /></button
></td
>
{/if}
<Svg className="icon-20" svg={clearIcon} />
</button>
</td>

<style lang="scss">
td.value {
max-width: 150px;
}
input {
max-width: 100%;
}
input.string {
// border: 0;
margin: 0;
// padding: 0.4rem;
width: 100%;
&:focus-visible {
border: 0;
box-shadow: none;
}
}
.btn-link {
padding: 0;
}
button.icon {
margin: 0;
padding: 0;
}
.checkbox {
width: 35px;
}
input:not([type='checkbox']).empty {
opacity: 0.6;
}
[type='checkbox'].empty {
background-color: lightgrey;
border-color: lightgray;
Expand Down
31 changes: 22 additions & 9 deletions demo/src/lib/layout/playground/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {getContext, setContext} from 'svelte';
import {hashObject$, updateHashValue} from '@agnos-ui/common/utils';
import type {WidgetDoc} from '@agnos-ui/doc/types';
import {normalizedType, textToLines} from '../../../app';
import type {PropsValues} from '@agnos-ui/common/propsValues';

type Playground = ReturnType<typeof createPlayground>;

Expand All @@ -19,20 +20,23 @@ interface PlaygroundProps {
config: Record<string, any>;
types: Record<string, string>;
doc: WidgetDoc;
listPropsValues: Record<string, PropsValues[]>;
}

function createSingleValueContext(valueType: 'config' | 'props', key: string, value: any, type: string) {
function createSingleValueContext(valueType: 'config' | 'props', key: string, value: any, type: string, selectValues?: PropsValues[]) {
function getTargetValue({target}: any) {
let value: any;
const targetValue = target.value.trim();
if (selectValues) {
return {value: targetValue};
}
switch (type) {
case 'boolean':
value = target.checked;
break;
case 'number':
value = +targetValue;
break;

default:
value = target.value;
break;
Expand All @@ -42,11 +46,12 @@ function createSingleValueContext(valueType: 'config' | 'props', key: string, va

const api = {
value: value ?? '',
selectValue: value?.value,
isEmpty: value === undefined,
onChange(e: any) {
updateHashValue(valueType, key, getTargetValue(e));
},

selectValues: selectValues,
clear() {
updateHashValue(valueType, key, undefined);
},
Expand All @@ -55,13 +60,21 @@ function createSingleValueContext(valueType: 'config' | 'props', key: string, va
return api;
}

function createValueContext(key: string, defaultValue: any, configValue: any, propValue: any, type: string = typeof defaultValue) {
function createValueContext(
key: string,
defaultValue: any,
configValue: any,
propValue: any,
type: string = typeof defaultValue,
selectValues?: PropsValues[]
) {
const api = {
key,
defaultValue,
config: createSingleValueContext('config', key, configValue, type),
prop: createSingleValueContext('props', key, propValue, type),
config: createSingleValueContext('config', key, configValue, type, selectValues),
prop: createSingleValueContext('props', key, propValue, type, selectValues),
type,
selectValues,
};

return api;
Expand All @@ -70,16 +83,16 @@ function createValueContext(key: string, defaultValue: any, configValue: any, pr
export type SingleValueContextApi = ReturnType<typeof createSingleValueContext>;
export type ValueContextApi = ReturnType<typeof createValueContext>;

export function createPlayground({config: defautConfig, types, doc}: PlaygroundProps) {
export function createPlayground({config: defaultConfig, types, doc, listPropsValues = {}}: PlaygroundProps) {
const docByProps: Record<string, WidgetDoc['props'][0]> = {};
for (const propDoc of doc.props) {
docByProps[propDoc.name] = propDoc;
}
const values$ = computed(() => {
const values: ReturnType<typeof createValueContext>[] = [];
const {config, props} = hashObject$();
for (const [key, value] of Object.entries(defautConfig)) {
values.push(createValueContext(key, value, config[key], props[key], types[key]));
for (const [key, value] of Object.entries(defaultConfig)) {
values.push(createValueContext(key, value, config[key], props[key], types[key], listPropsValues[key]));
}
return values;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
import {getAccordionDefaultConfig} from '@agnos-ui/core';
import sample from '@agnos-ui/samples/accordion/playground';
import doc from '../../../../../../../core/dist/api.json?accordion&extractApi';
import type {PropsValues} from '@agnos-ui/common/propsValues';
export let listPropsValues: {[key in keyof ReturnType<typeof getAccordionDefaultConfig>]?: PropsValues[]} = {
onShown: ['noop', 'log'],
onHidden: ['noop', 'log'],
itemTransition: ['collapse', 'fade'],
onItemShown: ['noop', 'log'],
onItemHidden: ['noop', 'log'],
onItemVisibleChange: ['noop', 'log'],
};
</script>

<Playground {sample} config={getAccordionDefaultConfig()} {doc} />
<Playground {sample} config={getAccordionDefaultConfig()} {doc} {listPropsValues} />
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
import {getAlertDefaultConfig} from '@agnos-ui/core';
import sample from '@agnos-ui/samples/alert/playground';
import doc from '../../../../../../../core/dist/api.json?alert&extractApi';
import type {PropsValues} from '@agnos-ui/common/propsValues';
export let listPropsValues: {[key in keyof ReturnType<typeof getAlertDefaultConfig>]?: PropsValues[]} = {
onVisibleChange: ['noop', 'log'],
onShown: ['noop', 'log'],
transition: ['fade'],
onHidden: ['noop', 'log'],
};
</script>

<Playground {sample} config={getAlertDefaultConfig()} {doc} />
<Playground {sample} config={getAlertDefaultConfig()} {doc} {listPropsValues} />
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
import {getModalDefaultConfig} from '@agnos-ui/core';
import sample from '@agnos-ui/samples/modal/playground';
import doc from '../../../../../../../core/dist/api.json?modal&extractApi';
import type {PropsValues} from '@agnos-ui/common/propsValues';
export let listPropsValues: {[key in keyof ReturnType<typeof getModalDefaultConfig>]?: PropsValues[]} = {
backdropTransition: ['fade'],
modalTransition: ['fade'],
onBeforeClose: ['noop', 'log'],
onHidden: ['noop', 'log'],
onShown: ['noop', 'log'],
onVisibleChange: ['noop', 'log'],
};
</script>

<Playground {sample} config={getModalDefaultConfig()} height={250} noresize {doc} />
<Playground {sample} config={getModalDefaultConfig()} height={250} noresize {doc} {listPropsValues} />
Loading

0 comments on commit 6ce8cf4

Please sign in to comment.