From c51250fd46cc84f3d043c90a9af6d0a7915af9d6 Mon Sep 17 00:00:00 2001
From: Alejandro Celaya
Date: Thu, 21 Sep 2023 14:34:42 +0200
Subject: [PATCH] Create SelectNext component replacing Select
---
src/components/input/Select.tsx | 1 +
src/components/input/SelectContext.ts | 10 +
src/components/input/SelectNext.tsx | 195 ++++++++++
src/components/input/index.ts | 2 +
src/components/input/test/SelectNext-test.js | 220 +++++++++++
src/index.ts | 2 +
.../components/patterns/input/SelectPage.tsx | 16 +-
.../patterns/prototype/SelectNextPage.tsx | 344 ++++++++++++++++++
src/pattern-library/routes.ts | 7 +
9 files changed, 793 insertions(+), 4 deletions(-)
create mode 100644 src/components/input/SelectContext.ts
create mode 100644 src/components/input/SelectNext.tsx
create mode 100644 src/components/input/test/SelectNext-test.js
create mode 100644 src/pattern-library/components/patterns/prototype/SelectNextPage.tsx
diff --git a/src/components/input/Select.tsx b/src/components/input/Select.tsx
index 2344ec1d6..db32bab64 100644
--- a/src/components/input/Select.tsx
+++ b/src/components/input/Select.tsx
@@ -23,6 +23,7 @@ const arrowImage = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000
/**
* Style a native `
+ <>
+
+ Select
is a presentational component that styles native{' '}
+ {''}
elements.
+
+
+ Select
is ,
+ use{' '}
+ SelectNext{' '}
+ instead.
+
+ >
}
>
diff --git a/src/pattern-library/components/patterns/prototype/SelectNextPage.tsx b/src/pattern-library/components/patterns/prototype/SelectNextPage.tsx
new file mode 100644
index 000000000..cfd39b157
--- /dev/null
+++ b/src/pattern-library/components/patterns/prototype/SelectNextPage.tsx
@@ -0,0 +1,344 @@
+import classnames from 'classnames';
+import { useCallback, useMemo, useState } from 'preact/hooks';
+
+import { ArrowLeftIcon, ArrowRightIcon } from '../../../../components/icons';
+import { IconButton, InputGroup } from '../../../../components/input';
+import Select from '../../../../components/input/SelectNext';
+import Library from '../../Library';
+
+const items = [
+ { id: '1', name: 'All students' },
+ { id: '2', name: 'Albert Banana' },
+ { id: '3', name: 'Bernard California' },
+ { id: '4', name: 'Cecelia Davenport' },
+ { id: '5', name: 'Doris Evanescence' },
+];
+
+function Select_({
+ disabled,
+ textOnly,
+ theItems = items,
+}: {
+ disabled?: boolean;
+ textOnly?: boolean;
+ theItems?: typeof items;
+}) {
+ const [value, setValue] = useState<(typeof theItems)[number]>();
+
+ return (
+
+ {value.name}
+ {!textOnly && (
+
+ {value.id}
+
+ )}
+ >
+ ) : disabled ? (
+ <>This is disabled>
+ ) : (
+ <>Select one...>
+ )
+ }
+ disabled={disabled}
+ >
+ {theItems.map(item => (
+
+ {() =>
+ textOnly ? (
+ <>{item.name}>
+ ) : (
+ <>
+ {item.name}
+
+
+ {item.id}
+
+ >
+ )
+ }
+
+ ))}
+
+ );
+}
+
+function InputGroupSelect_() {
+ const [selected, setSelected] = useState<(typeof items)[number]>();
+ const selectedIndex = useMemo(
+ () => (!selected ? -1 : items.findIndex(item => item === selected)),
+ [selected],
+ );
+ const next = useCallback(() => {
+ const newIndex = selectedIndex + 1;
+ setSelected(
+ (items[newIndex]?.id === '4' ? items[newIndex + 1] : items[newIndex]) ??
+ selected,
+ );
+ }, [selected, selectedIndex]);
+ const previous = useCallback(() => {
+ const newIndex = selectedIndex - 1;
+ setSelected(
+ (items[newIndex]?.id === '4' ? items[newIndex - 1] : items[newIndex]) ??
+ selected,
+ );
+ }, [selected, selectedIndex]);
+
+ return (
+
+
+
+
+ {selected.name}
+
+ {selected.id}
+
+ >
+ ) : (
+ <>Select one...>
+ )
+ }
+ >
+ {items.map(item => (
+
+ {({ disabled }) => (
+ <>
+
+ {item.name}
+
+
+
+ {item.id}
+
+ >
+ )}
+
+ ))}
+
+
+ = items.length - 1}
+ />
+
+ );
+}
+
+export default function SelectNextPage() {
+ return (
+
+ SelectNext
is a presentational component which behaves
+ like the native {''}
element.
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SelectNext
toggles a listbox where Options
+ {"'"} UI can be customized and values can be objects.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ({
+ id: `1${id}`,
+ name: `1 ${name}`,
+ })),
+ ...items.map(({ id, name }) => ({
+ id: `2${id}`,
+ name: `2 ${name}`,
+ })),
+ ...items.map(({ id, name }) => ({
+ id: `3${id}`,
+ name: `3 ${name}`,
+ })),
+ ...items.map(({ id, name }) => ({
+ id: `4${id}`,
+ name: `4 ${name}`,
+ })),
+ ...items.map(({ id, name }) => ({
+ id: `5${id}`,
+ name: `5 ${name}`,
+ })),
+ ...items.map(({ id, name }) => ({
+ id: `6${id}`,
+ name: `6 ${name}`,
+ })),
+ ]}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SelectNext
accepts all standard{' '}
+
+ presentational component props
+
+
+
+
+ The content to be displayed in the toggle button.
+
+
+ ComponentChildren
+
+
+
+
+
+
+ Represents currently selected Option.
+
+
+ T
+
+
+
+
+
+
+ A callback invoked every time selected value changes.
+
+
+ (newValue: T) => void
+
+
+
+
+
+
+ Whether the Select is disabled or not.
+
+
+ boolean
+
+
+ undefined
+
+
+
+
+
+
+
+ SelectNext
is meant to be used as a controlled
+ component.
+
+
+ ();
+ return (
+
+ {value.name}
+
+ {value.id}
+
+ >
+ ) : (
+ <>Select one...>
+ )
+ }
+ >
+ {items.map(item => (
+
+ {() => (
+ <>
+ {item.name}
+
+
+ {item.id}
+
+ >
+ )}
+
+ ))}
+
+ );
+}`}
+ />
+
+
+
+ );
+}
diff --git a/src/pattern-library/routes.ts b/src/pattern-library/routes.ts
index 5854f20b1..3de50d065 100644
--- a/src/pattern-library/routes.ts
+++ b/src/pattern-library/routes.ts
@@ -32,6 +32,7 @@ import PointerButtonPage from './components/patterns/navigation/PointerButtonPag
import TabPage from './components/patterns/navigation/TabPage';
import LMSContentButtonPage from './components/patterns/prototype/LMSContentButtonPage';
import LMSContentSelectionPage from './components/patterns/prototype/LMSContentSelectionPage';
+import SelectNextPage from './components/patterns/prototype/SelectNextPage';
import SharedAnnotationsPage from './components/patterns/prototype/SharedAnnotationsPage';
import TabbedDialogPage from './components/patterns/prototype/TabbedDialogPage';
import SliderPage from './components/patterns/transition/SliderPage';
@@ -195,6 +196,12 @@ const routes: PlaygroundRoute[] = [
component: OptionButtonPage,
route: '/input-option-button',
},
+ {
+ title: 'SelectNext',
+ group: 'input',
+ component: SelectNextPage,
+ route: '/input-select-next',
+ },
{
title: 'Select',
group: 'input',