@public-ui/sample-react 1.7.0-rc.6 → 1.7.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@public-ui/sample-react",
3
- "version": "1.7.0-rc.6",
3
+ "version": "1.7.0-rc.7",
4
4
  "description": "This app contains samples for the KoliBri/Public UI",
5
5
  "license": "EUPL-1.2",
6
6
  "scripts": {
@@ -20,16 +20,16 @@
20
20
  "kolibri-sample-react-test-build": "test-build.sh"
21
21
  },
22
22
  "dependencies": {
23
- "@leanup/stack": "1.3.47",
24
- "@leanup/stack-react": "1.3.44",
25
- "@leanup/stack-webpack": "1.3.47",
23
+ "@leanup/stack": "1.3.48",
24
+ "@leanup/stack-react": "1.3.48",
25
+ "@leanup/stack-webpack": "1.3.48",
26
26
  "@public-oss/kolibri-themes": "0.0.3",
27
- "@public-ui/components": "1.7.0-rc.6",
28
- "@public-ui/react": "1.7.0-rc.6",
29
- "@public-ui/themes": "1.7.0-rc.6",
27
+ "@public-ui/components": "1.7.0-rc.7",
28
+ "@public-ui/react": "1.7.0-rc.7",
29
+ "@public-ui/themes": "1.7.0-rc.7",
30
30
  "@types/react": "18.2.21",
31
31
  "@types/react-dom": "18.2.7",
32
- "@unocss/preset-mini": "0.55.7",
32
+ "@unocss/preset-uno": "0.55.7",
33
33
  "@unocss/webpack": "0.55.7",
34
34
  "ajv": "8.12.0",
35
35
  "chromedriver": "116.0.0",
@@ -59,8 +59,5 @@
59
59
  "tsconfig.json",
60
60
  "unocss.config.ts",
61
61
  "webpack.config.js"
62
- ],
63
- "publishConfig": {
64
- "registry": "https://registry.npmjs.org/"
65
- }
62
+ ]
66
63
  }
@@ -1,5 +1,4 @@
1
1
  module.exports = {
2
- ...require('@leanup/stack/prettier.config'),
3
2
  printWidth: 160,
4
3
  singleQuote: true,
5
4
  useTabs: true,
package/src/App.tsx CHANGED
@@ -1,29 +1,18 @@
1
- import React, { useMemo } from 'react';
2
- import { Navigate, Route, Routes } from 'react-router-dom';
1
+ import React, { FC } from 'react';
2
+ import { Navigate, Route, Routes, useSearchParams } from 'react-router-dom';
3
3
  import { Route as MyRoute, Routes as MyRoutes } from './shares/types';
4
4
 
5
5
  import { Option } from '@public-ui/components';
6
- import { KolAlert, KolButton, KolSelect, KolVersion } from '@public-ui/react';
7
- import { FC, useState } from 'react';
6
+ import { KolAlert } from '@public-ui/react';
8
7
  import { ROUTES } from './shares/routes';
9
- import { THEME_OPTIONS, Theme } from './shares/theme';
8
+ import { Theme, THEME_OPTIONS } from './shares/theme';
10
9
  import PackageJson from '../package.json';
11
- import { getTheme, setTheme, setStorage, getThemeName } from './shares/store';
12
-
13
- const THEME_REGEX = /theme=([^&]+)/;
10
+ import { getTheme, getThemeName, setStorage, setTheme } from './shares/store';
11
+ import { Sidebar } from './components/Sidebar';
12
+ import { useLocation } from 'react-router';
14
13
 
15
14
  setStorage(localStorage);
16
15
 
17
- const getThemeFromLocation = () => {
18
- if (THEME_REGEX.test(window.location.hash)) {
19
- const match = window.location.hash.match(THEME_REGEX);
20
- if (Array.isArray(match) && match.length > 0) {
21
- return match[0].replace(THEME_REGEX, '$1').toLowerCase();
22
- }
23
- }
24
- return getTheme();
25
- };
26
-
27
16
  const getRouteList = (routes: MyRoutes, offset = '/'): string[] => {
28
17
  let list: string[] = [];
29
18
  for (const key in routes) {
@@ -88,168 +77,52 @@ const getRouteTree = (routes: MyRoutes): ReturnType<typeof Route>[] => {
88
77
  };
89
78
 
90
79
  const ROUTE_LIST = getRouteList(ROUTES);
80
+ const ROUTE_TREE = getRouteTree(ROUTES);
91
81
 
92
- const clearHash = (str: string) => str.replace(/\?.*/g, '').replace(/^#/g, '');
93
-
94
- const getIndexOfRoute = (str: string) => {
95
- return ROUTE_LIST.indexOf(clearHash(str));
96
- };
97
-
98
- type CustomRoute = { label: string; value: string };
99
- const componentList: CustomRoute[] = [];
82
+ const componentList: Map<string, Option<string>> = new Map();
100
83
  ROUTE_LIST.forEach((route) => {
101
84
  const routeSplit = route.split('/');
102
- if (routeSplit.pop() === 'basic') componentList.push({ label: routeSplit[1], value: route });
85
+ if (!componentList.has(routeSplit[1])) {
86
+ componentList.set(routeSplit[1], {
87
+ label: routeSplit[1],
88
+ value: route,
89
+ });
90
+ }
103
91
  });
104
92
 
105
- function getComponentFromSample(url: string): string {
106
- const routeSplit = url.split('/');
107
- routeSplit[2] = 'basic';
108
- return routeSplit.join('/');
109
- }
110
-
111
93
  export const App: FC = () => {
112
- const [theme] = useState(getThemeFromLocation());
113
- const [sample, setSample] = useState(clearHash(window.location.hash));
114
- const [active, setActive] = useState(false);
115
- const [firstComponentChangeEvent, setFirstComponentChangeEvent] = useState(true);
94
+ const routerLocation = useLocation();
95
+ const [searchParams, setSearchParams] = useSearchParams();
96
+ const theme = searchParams.get('theme') ?? getTheme();
97
+ const hideMenus = searchParams.has('hideMenus');
116
98
 
117
- const currentComponent = useMemo(() => {
118
- return getComponentFromSample(sample);
119
- }, [sample]);
99
+ setTheme(theme as Theme); // set for `getTheme` usages within the application
120
100
 
121
101
  document.title = `KoliBri-Handout - ${getThemeName(getTheme())} | v${PackageJson.version}`;
122
102
  document.body.setAttribute('class', theme);
123
103
  document.body.dataset.theme = theme;
124
104
 
125
- const catchRef = () => {
126
- setTimeout(() => {
127
- setActive(true);
128
- }, 500);
129
- };
130
-
131
- const componentSelectOn = {
132
- onChange: (_e: Event, v: unknown) => {
133
- /**
134
- * Drop first event as a temporary bugfix for the following issue:
135
- * When navigated to a component example which is not "basic" it would navigate away from it on the first event, because the select only stores the basic routes.
136
- * e.g. accordion/header would become accordion/basic.
137
- * This problem will become obsolete when the select gets replaced with a proper navigation (https://github.com/public-ui/kolibri/issues/5064)
138
- */
139
- if (firstComponentChangeEvent) {
140
- setFirstComponentChangeEvent(false);
141
- return;
142
- }
143
-
144
- const path = (v as string[])[0];
145
- setSample(path);
146
- window.location.href = `#${path}?theme=${theme}`;
147
- },
148
- };
149
-
150
- const on = {
151
- onChange: (_event: Event, value: unknown) => {
152
- if (active) {
153
- value = Array.isArray(value) ? value[0] : value;
154
- setTheme(value as Theme);
155
- window.location.href =
156
- window.location.href
157
- .replace(THEME_REGEX, '')
158
- .replace(/(\?|&{1,})$/g, '')
159
- .replace(/&{2,}/g, '&') + `?theme=${value as string}`;
160
- window.location.reload();
161
- }
162
- },
163
- };
164
-
165
- const next = {
166
- onClick: () => {
167
- let idx = getIndexOfRoute(window.location.hash);
168
- if (idx >= ROUTE_LIST.length - 1) {
169
- idx = 0;
170
- } else {
171
- idx += 1;
172
- }
173
- setSample(clearHash(ROUTE_LIST[idx]));
174
- window.location.href = `#${ROUTE_LIST[idx]}?theme=${theme}`;
175
- },
176
- };
177
-
178
- const prev = {
179
- onClick: () => {
180
- let idx = getIndexOfRoute(window.location.hash);
181
- if (idx <= 0) {
182
- idx = ROUTE_LIST.length - 1;
183
- } else {
184
- idx -= 1;
185
- }
186
- setSample(clearHash(ROUTE_LIST[idx]));
187
- window.location.href = `#${ROUTE_LIST[idx]}?theme=${theme}`;
188
- },
105
+ const handleThemeChange = (theme: unknown) => {
106
+ setSearchParams({ theme: theme as string });
107
+ window.location.reload();
189
108
  };
190
109
 
191
110
  return (
192
- <div className="grid gap-4" data-theme={theme} ref={catchRef}>
193
- <div className="no-print grid gap-4 toolbar">
194
- <dl>
195
- <dt>Beispiel:</dt>
196
- <dd>
197
- <strong>
198
- {/* <KolLink _href={`${window.location.href}?theme=${theme}`} _label={sample} _target="codesandbox" /> */}
199
- {sample.replace(/\//g, ' ')}
200
- </strong>{' '}
201
- ({getIndexOfRoute(window.location.hash) + 1}/{ROUTE_LIST.length})
202
- </dd>
203
- <dd>
204
- <KolVersion _version={PackageJson.version}></KolVersion>
205
- </dd>
206
- </dl>
207
- {active && (
208
- <>
209
- <KolButton
210
- _ariaLabel="Weiter zum nächsten Komponenten-Beispiel"
211
- _icon="codicon codicon-arrow-right"
212
- _hideLabel
213
- _label="Weiter"
214
- _on={next}
215
- _tooltipAlign="left"
216
- />
217
- <KolButton
218
- _ariaLabel="Weiter zum nächsten Komponenten-Beispiel"
219
- _icon="codicon codicon-arrow-left"
220
- _hideLabel
221
- _label="Zurück"
222
- _on={prev}
223
- _tooltipAlign="right"
224
- _variant="ghost"
225
- />
226
- </>
227
- )}
228
- <KolSelect
229
- className="col-span-2 sm:col-auto"
230
- _disabled={!active}
231
- _hideLabel
232
- _label="Komponente wechseln"
233
- _id="theme-toggle"
234
- _list={componentList}
235
- _on={componentSelectOn}
236
- _value={[currentComponent]}
237
- ></KolSelect>
238
- <KolSelect
239
- _label="Theme wechseln"
240
- className="col-span-2 sm:col-auto"
241
- _hideLabel
242
- _disabled={!active}
243
- _id="theme-toggle"
244
- _list={THEME_OPTIONS}
245
- _on={on}
246
- _value={[theme]}
247
- ></KolSelect>
248
- </div>
249
- <hr aria-hidden="true" />
111
+ <div className={!hideMenus ? 'app-container' : ''} data-theme={theme}>
112
+ {!hideMenus && (
113
+ <Sidebar
114
+ version={PackageJson.version}
115
+ theme={theme}
116
+ sample={routerLocation.pathname}
117
+ routes={ROUTES}
118
+ routeList={ROUTE_LIST}
119
+ onThemeChange={handleThemeChange}
120
+ />
121
+ )}
122
+
250
123
  <div className="p-4">
251
124
  <Routes>
252
- {getRouteTree(ROUTES)}
125
+ {ROUTE_TREE}
253
126
  <Route path="*" element={<KolAlert _type="info">This code example has not been migrated yet - it&#39;s coming soon!</KolAlert>} />
254
127
  </Routes>
255
128
  </div>
@@ -0,0 +1,81 @@
1
+ import React, { FC, useState } from 'react';
2
+ import { KolButton, KolHeading, KolLink, KolSelect, KolVersion } from '@public-ui/react';
3
+ import { THEME_OPTIONS } from '../shares/theme';
4
+ import { Routes } from '../shares/types';
5
+
6
+ type Props = {
7
+ version: string;
8
+ theme: string;
9
+ routes: Routes;
10
+ routeList: string[];
11
+ sample: string;
12
+ onThemeChange: (theme: unknown) => void;
13
+ };
14
+
15
+ export const Sidebar: FC<Props> = ({ version, theme, routes, routeList, sample, onThemeChange }) => {
16
+ /* KolSelect calls onChange initially by design - work around this with a state variable */
17
+ const [isFirstThemeSelectChange, setIsFirstThemeSelectChange] = useState(true);
18
+
19
+ const getIndexOfSample = () => routeList.indexOf(sample);
20
+ const formatSampleAsLabel = () => sample.replace(/\//g, ' ');
21
+
22
+ const handleThemeSelectChange = (_event: Event, value: unknown) => {
23
+ if (isFirstThemeSelectChange) {
24
+ setIsFirstThemeSelectChange(false);
25
+ } else {
26
+ onThemeChange((value as [string])[0]);
27
+ }
28
+ };
29
+
30
+ const handleLinkClick = (event: Event) => {
31
+ location.replace((event.target as HTMLLinkElement).href); // KoliBri prevents the default click behavior as soon as an event listener is set, so we need to reimplement it.
32
+ document.documentElement.scrollIntoView({ behavior: 'smooth' });
33
+ // @todo set focus?
34
+ };
35
+
36
+ const handlePreviousClick = () => {
37
+ const currentIndex = getIndexOfSample();
38
+ const nextIndex = currentIndex === 0 ? routeList.length - 1 : currentIndex - 1;
39
+ location.replace(`#${routeList[nextIndex]}`);
40
+ };
41
+
42
+ const handleNextClick = () => {
43
+ const currentIndex = getIndexOfSample();
44
+ const nextIndex = currentIndex === routeList.length - 1 ? 0 : currentIndex + 1;
45
+ location.replace(`#${routeList[nextIndex]}`);
46
+ };
47
+
48
+ return (
49
+ <aside className="app-sidebar p-4">
50
+ <div className="flex flex-justify-between flex-items-center">
51
+ <KolHeading _label="KoliBri React"></KolHeading>
52
+ <KolVersion _version={version}></KolVersion>
53
+ </div>
54
+
55
+ <KolSelect _label="Theme wählen" _list={THEME_OPTIONS} _on={{ onChange: handleThemeSelectChange }} _value={[theme]} class="mt"></KolSelect>
56
+
57
+ <KolHeading _label="Komponenten" _level={2} className="block mt"></KolHeading>
58
+ <div className="flex flex-justify-between flex-items-center mt">
59
+ <KolButton _icon="codicon codicon-arrow-left" _hideLabel _label="Vorherige Komponente auswählen" _on={{ onClick: handlePreviousClick }} />
60
+ {formatSampleAsLabel()} ({getIndexOfSample() + 1}/{routeList.length})
61
+ <KolButton _icon="codicon codicon-arrow-right" _hideLabel _label="Nächste Komponente auswählen" _on={{ onClick: handleNextClick }} />
62
+ </div>
63
+ <nav className="block mt">
64
+ <ul className="m0 p0 list-inside">
65
+ {Object.entries(routes).map(([parentName, children]) => (
66
+ <li key={parentName} className="mt-2">
67
+ {parentName}
68
+ <ul className="list-inside ml p0">
69
+ {Object.keys(children).map((childName) => (
70
+ <li key={`${parentName}/${childName}`}>
71
+ <KolLink _label={childName} _href={`#/${parentName}/${childName}`} _on={{ onClick: handleLinkClick }} />
72
+ </li>
73
+ ))}
74
+ </ul>
75
+ </li>
76
+ ))}
77
+ </ul>
78
+ </nav>
79
+ </aside>
80
+ );
81
+ };
@@ -2,7 +2,7 @@ import { Routes } from '../../shares/types';
2
2
  import { SplitButtonBasic } from './basic';
3
3
 
4
4
  export const SPLIT_BUTTON_ROUTES: Routes = {
5
- splitButton: {
5
+ 'split-button': {
6
6
  basic: SplitButtonBasic,
7
7
  },
8
8
  };
@@ -1,5 +1,5 @@
1
1
  import { isTheme, Store, Theme } from './theme';
2
- import PackageJson from '../../node_modules/@public-ui/components/package.json';
2
+ import PackageJson from '@public-ui/components/package.json';
3
3
  import { THEME_OPTIONS } from './theme';
4
4
  import { Option } from '@public-ui/components';
5
5
 
package/src/style.scss CHANGED
@@ -19,71 +19,20 @@ hr {
19
19
  grid-template-columns: auto auto;
20
20
  }
21
21
 
22
- .toolbar {
23
- grid-template-columns: auto 1fr auto 1fr auto;
24
- place-items: center;
22
+ .app-container {
23
+ display: grid;
24
+ grid-template-columns: 360px auto;
25
+ height: 100%;
25
26
  }
26
27
 
27
- .toolbar kol-button[_label="Zurück"] {
28
- order: 1;
29
- }
30
-
31
- .toolbar dl {
32
- order: 2;
33
- display: flex;
34
- gap: 0.5em;
35
- justify-self: start;
36
- place-items: center;
37
- }
38
-
39
- .toolbar dd {
40
- margin: 0;
41
- }
42
-
43
- .toolbar kol-select {
44
- order: 3;
45
- }
46
-
47
- .toolbar kol-button[_label="Weiter"] {
48
- order: 4;
49
- }
50
-
51
- @media only screen and (max-width: 1024px) {
52
- .toolbar {
53
- display: grid;
54
- gap: 1rem;
55
- grid-template-columns: 1fr 1fr;
56
- }
57
-
58
- .toolbar kol-button[_label="Zurück"] {
59
- order: 3;
60
- }
61
-
62
- .toolbar dl {
63
- order: 1;
64
- }
65
-
66
- .toolbar kol-select {
67
- order: 2;
68
- }
69
-
70
- .toolbar kol-button[_label="Weiter"] {
71
- order: 4;
72
- }
73
- }
74
-
75
- @media only screen and (max-width: 512px) {
76
-
77
- .toolbar dl,
78
- .toolbar kol-select {
79
- grid-column: span 2;
80
- }
28
+ .app-sidebar {
29
+ border-right: 1px solid gray;
30
+ font-family: sans-serif;
81
31
  }
82
32
 
83
33
  @media print {
84
-
85
34
  .no-print,
86
35
  .no-print * {
87
36
  display: none !important;
88
37
  }
89
- }
38
+ }
package/unocss.config.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { defineConfig } from '@unocss/webpack';
2
- import { presetMini } from '@unocss/preset-mini';
2
+ import { presetUno } from '@unocss/preset-uno';
3
3
 
4
4
  // ts-prune-ignore-next
5
5
  export default defineConfig({
6
- presets: [presetMini()],
6
+ presets: [presetUno()],
7
7
  });