@codeleap/web 3.21.9 → 3.22.1

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": "@codeleap/web",
3
- "version": "3.21.9",
3
+ "version": "3.22.1",
4
4
  "main": "src/index.ts",
5
5
  "repository": {
6
6
  "url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
@@ -44,7 +44,8 @@
44
44
  "slick-carousel": "^1.8.1",
45
45
  "url-parse": "^1.5.10",
46
46
  "uuid": "^8.3.2",
47
- "zustand": "^4.4.1"
47
+ "zustand": "^4.4.1",
48
+ "@fastify/deepmerge": "1.3.0"
48
49
  },
49
50
  "peerDependencies": {
50
51
  "@codeleap/common": "*",
@@ -21,7 +21,6 @@ import {
21
21
  export * from './styles'
22
22
 
23
23
  export type SliderProps = Partial<Omit<PrimitiveSliderProps, 'value' | 'onValueChange'>> & Pick<InputBaseProps, 'disabled' | 'debugName' | 'description' | 'label'> & {
24
- debounce?: number | null
25
24
  indicatorLabel?: {
26
25
  order?: number[]
27
26
  separator?: string
@@ -44,7 +43,7 @@ export type TrackMarkProps = {
44
43
  }
45
44
 
46
45
  const DefaultSliderTrackMark = (props: TrackMarkProps) => {
47
- const { index, content, style } = props
46
+ const { style } = props
48
47
 
49
48
  if (!TypeGuards.isString(props.content)) {
50
49
  return <React.Fragment>
@@ -65,8 +64,8 @@ export const Slider = (props: SliderProps) => {
65
64
  } = selectInputBaseProps(props)
66
65
 
67
66
  const {
68
- debounce = null,
69
67
  onValueChange,
68
+ onValueCommit,
70
69
  value: _value,
71
70
  label,
72
71
  debugName,
@@ -82,7 +81,7 @@ export const Slider = (props: SliderProps) => {
82
81
  min = 0,
83
82
  indicatorLabel = null,
84
83
  description = null,
85
- minStepsBetweenThumbs = 8,
84
+ minStepsBetweenThumbs = 0,
86
85
  step = 1,
87
86
  onPressThumbSetValue = false,
88
87
  onPressThumb = null,
@@ -91,6 +90,7 @@ export const Slider = (props: SliderProps) => {
91
90
 
92
91
  const isUniqueValue = !TypeGuards.isArray(_value)
93
92
  const value = isUniqueValue ? [_value] : _value
93
+
94
94
  const _defaultValue = TypeGuards.isArray(defaultSliderValue) ? defaultSliderValue : [defaultSliderValue]
95
95
 
96
96
  const defaultValueRef = useRef<PrimitiveSliderProps['defaultValue']>(_defaultValue)
@@ -104,34 +104,12 @@ export const Slider = (props: SliderProps) => {
104
104
 
105
105
  const SliderTrackMark = trackMarkComponent
106
106
 
107
- const currentThumbRef = useRef(null)
108
-
109
107
  const handleChange: SliderProps['onValueChange'] = (newValue: Array<number>) => {
110
- if (isUniqueValue) {
111
- onValueChange(newValue?.[0])
112
- return
113
- }
114
-
115
- const copyValue = [...value]
116
-
117
- const i = currentThumbRef.current
118
- const _newValue = newValue[currentThumbRef.current]
119
-
120
- const hasLeftThumb = i !== 0
121
- const hasRightThumb = i + 1 < newValue.length
122
-
123
- const previousThumbValue = hasLeftThumb ? (copyValue[i - 1] + minStepsBetweenThumbs) : null
124
- const nextThumbValue = hasRightThumb ? (copyValue[i + 1] - minStepsBetweenThumbs) : null
125
-
126
- if (previousThumbValue && _newValue <= previousThumbValue) {
127
- copyValue[i] = previousThumbValue
128
- } else if (nextThumbValue && _newValue >= nextThumbValue) {
129
- copyValue[i] = nextThumbValue
130
- } else {
131
- copyValue[i] = _newValue
132
- }
108
+ onValueChange(isUniqueValue ? newValue?.[0] : newValue)
109
+ }
133
110
 
134
- onValueChange(copyValue)
111
+ const handleValueCommit = (newValue: Array<number>) => {
112
+ onValueCommit?.(newValue)
135
113
  }
136
114
 
137
115
  const variantStyles = useDefaultComponentStyle<'u:Slider', typeof SliderPresets>('u:Slider', {
@@ -234,15 +212,15 @@ export const Slider = (props: SliderProps) => {
234
212
  <SliderContainer
235
213
  {...sliderProps}
236
214
  step={step}
237
- minStepsBetweenThumbs={minStepsBetweenThumbs}
238
- style={containerStyle}
239
- defaultValue={defaultValue}
240
- value={value}
241
- onValueCommit={() => null}
242
- onValueChange={handleChange}
243
215
  min={min}
244
216
  max={max}
245
217
  disabled={disabled}
218
+ defaultValue={defaultValue}
219
+ onValueCommit={handleValueCommit}
220
+ onValueChange={handleChange}
221
+ style={containerStyle}
222
+ value={value}
223
+ minStepsBetweenThumbs={minStepsBetweenThumbs}
246
224
  >
247
225
  <SliderTrack style={trackStyle}>
248
226
  <SliderRange style={selectedTrackStyle} />
@@ -256,10 +234,7 @@ export const Slider = (props: SliderProps) => {
256
234
  onClick={() => {
257
235
  if (onPressThumbSetValue) onValueChange?.(value)
258
236
  if (TypeGuards.isFunction(onPressThumb)) onPressThumb?.(value, i)
259
-
260
- currentThumbRef.current = i
261
237
  }}
262
- onMouseEnter={() => currentThumbRef.current = i}
263
238
  />
264
239
  ))}
265
240
  </SliderContainer>
package/src/index.ts CHANGED
@@ -1,12 +1,5 @@
1
1
  export * from './components/components'
2
- export * from './lib/hooks'
3
- export * from './lib/utils'
4
2
  export * from './types/utility'
5
- export * from './lib/useSearchParams'
6
- export * from './lib/useBreakpointMatch'
7
- export * from './lib/usePopState'
8
- export * from './lib/useAnimatedStyle'
3
+ export * from './lib'
4
+
9
5
  export { default as Toast } from './lib/Toast'
10
- export * from './lib/keyboard'
11
- export * from './lib/localStorage'
12
- export * from './lib/modal'
package/src/lib/index.ts CHANGED
@@ -7,3 +7,6 @@ export * from './useClick'
7
7
  export * from './ListMasonry'
8
8
  export * from './localStorage'
9
9
  export * from './useAnimatedStyle'
10
+ export * from './navigation'
11
+ export * from './modal'
12
+ export * from './keyboard'
@@ -0,0 +1,280 @@
1
+ import { AnyValue, Config, History, Navigator, RouteParams, RoutePath, Routes } from './types'
2
+ import deepmerge from '@fastify/deepmerge'
3
+
4
+ const IS_SSR = typeof window === 'undefined' || typeof history === 'undefined'
5
+
6
+ const defaultConfig: Partial<Config> = {
7
+ historyEnabled: false,
8
+ getMetadata: () => {}
9
+ }
10
+
11
+ export type {
12
+ Navigator,
13
+ Routes,
14
+ }
15
+
16
+ export class Navigation<O extends object, R extends object = {}> {
17
+ private _history: History = {}
18
+
19
+ private config: Config = defaultConfig
20
+
21
+ get history() {
22
+ return this._history
23
+ }
24
+
25
+ private putHistory(path: RoutePath, info: any = {}) {
26
+ const idx = Object.keys(this._history).length + 1
27
+
28
+ const origin = IS_SSR ? null : window?.location?.origin
29
+
30
+ const value: History = {
31
+ [idx]: {
32
+ origin,
33
+ date: new Date(),
34
+ path,
35
+ metadata: this.config?.getMetadata?.(),
36
+ info,
37
+ }
38
+ }
39
+
40
+ this._history = this.merge(this._history, value)
41
+ }
42
+
43
+ private merge(obj: object, addObj: AnyValue) {
44
+ return deepmerge({ all: true })(
45
+ obj ?? {},
46
+ addObj ?? {},
47
+ )
48
+ }
49
+
50
+ private navigator: Navigator<O> = null
51
+
52
+ private routes: R = {} as R
53
+
54
+ constructor(
55
+ routes: R,
56
+ navigator: Navigator<O>,
57
+ config: Config = {},
58
+ ) {
59
+ this.navigator = navigator
60
+ this.routes = routes
61
+ this.config = this.merge(this.config, config)
62
+ }
63
+
64
+ /**
65
+ * Checks if the user is on a certain route based on the parameters passed
66
+ * @param route Route that will be used to direct
67
+ * @param routeParams Parameters that will be applied to the route
68
+ * @param exact Accurate path checking - default false
69
+ * @returns Is on the route - boolean
70
+ */
71
+ public isCurrentRoute<T extends keyof Routes<R>>(
72
+ route: T,
73
+ // @ts-expect-error
74
+ routeParams: Record<Routes<R>[T], string|number> = {} as any,
75
+ exact: boolean = false,
76
+ ) {
77
+ if (IS_SSR) return false
78
+
79
+ let path = window?.location?.pathname
80
+
81
+ // @ts-ignore
82
+ const routePath = this.getPathWithParams(route, routeParams)
83
+
84
+ const isRootPath = routePath === '/'
85
+
86
+ if (isRootPath) {
87
+ const { pathname, origin, href } = window.location || {}
88
+
89
+ path = href?.replace(path, '')
90
+ path = path?.replace(origin, '')
91
+
92
+ return !path || pathname == routePath
93
+ }
94
+
95
+ if (exact) {
96
+ return path?.endsWith(routePath)
97
+ }
98
+
99
+ if (path?.includes(routePath)) {
100
+ return true
101
+ }
102
+
103
+ return false
104
+ }
105
+
106
+ /**
107
+ * Get the path from the route
108
+ * @param route Route that will be used to direct
109
+ * @returns Path - string
110
+ */
111
+ public getPath(route: keyof Routes<R>): string {
112
+ let path = this.routes
113
+
114
+ // @ts-ignore
115
+ if (route?.includes('.')) {
116
+ // @ts-ignore
117
+ const indexesAccess = route?.split('.')
118
+
119
+ for (const index of indexesAccess) {
120
+ path = path?.[index]
121
+ }
122
+ } else {
123
+ // @ts-ignore
124
+ path = path?.[route]
125
+ }
126
+
127
+ return String(path)?.trim?.()
128
+ }
129
+
130
+ /**
131
+ * Get the path from the route and route params
132
+ * @param route Route that will be used to direct
133
+ * @param routeParams Parameters that will be applied to the route
134
+ * @returns Path - string
135
+ */
136
+ public getPathWithParams<T extends keyof Routes<R>>(
137
+ route: T,
138
+ // @ts-expect-error
139
+ routeParams: Record<Routes<R>[T], string|number> = {} as any
140
+ ) {
141
+ let path = this.getPath(route)
142
+
143
+ for (const key in routeParams) {
144
+ const value = String(routeParams?.[key])
145
+
146
+ const searchPartial = `{{${key}}}`
147
+
148
+ if (path?.includes(searchPartial)) {
149
+ path = path?.replace(searchPartial, encodeURIComponent(value))
150
+ }
151
+ }
152
+
153
+ if (!path?.startsWith('/')) {
154
+ path = '/' + path
155
+ }
156
+
157
+ if (!path?.endsWith('/')) {
158
+ path = path + '/'
159
+ }
160
+
161
+ return path?.trim()
162
+ }
163
+
164
+ /**
165
+ * Function to navigate to the previous page, if history is enabled, the penultimate record will be used,
166
+ * otherwise the browser's own api with "history.back()"
167
+ */
168
+ public goBack() {
169
+ if (IS_SSR) return
170
+
171
+ if (!this.config.historyEnabled) {
172
+ history?.back?.()
173
+ return
174
+ }
175
+
176
+ const lastIdx = Object.keys(this.history)?.length
177
+
178
+ const historyData = this.history[lastIdx - 1]
179
+
180
+ if (!historyData) {
181
+ throw new Error('Not find back route')
182
+ }
183
+
184
+ const info = this.merge(historyData?.info, {
185
+ 'action': 'goBack'
186
+ })
187
+
188
+ this.to(historyData?.path, historyData?.info?.options ?? {}, info)
189
+ }
190
+
191
+ /**
192
+ * Main function to navigate between the app using the route system with dynamic parameters
193
+ * @param route Route that will be used to direct
194
+ * @param options Route parameters (marked by {{}}), which will be automatically shown if they exist, and navigator options and route queryParams can also be passed through the "params" property
195
+ */
196
+ public navigate<T extends keyof Routes<R>>(
197
+ route: T,
198
+ // @ts-expect-error
199
+ options: Record<Routes<R>[T], string|number> & O & { params?: RouteParams } = {} as any
200
+ ) {
201
+ // @ts-ignore
202
+ let path = this.getPath(route)
203
+
204
+ let _options = {}
205
+ let params = null
206
+ let routeParams = {}
207
+
208
+ const queryParamsKey = 'params'
209
+
210
+ for (const key in options) {
211
+ const value = options?.[key]
212
+
213
+ const searchPartial = `{{${key}}}`
214
+
215
+ if (path?.includes(searchPartial)) {
216
+ path = path?.replace(searchPartial, encodeURIComponent(String(value)))
217
+
218
+ routeParams = this.merge(routeParams, { [key]: String(value) })
219
+ } else if (key == queryParamsKey) {
220
+ params = value
221
+ } else {
222
+ _options = this.merge(_options, { [key]: value })
223
+ }
224
+ }
225
+
226
+ if (!path?.startsWith('/')) {
227
+ path = '/' + path
228
+ }
229
+
230
+ if (typeof params === 'object') {
231
+ let searchParams = null
232
+
233
+ for (const paramKey in (params ?? {})) {
234
+ const value = params?.[paramKey]
235
+ const param = `${paramKey}=${encodeURIComponent(value)}`
236
+ const separator = searchParams == null ? '' : '&'
237
+
238
+ searchParams = `${searchParams ?? ''}${separator}${param}`
239
+ }
240
+
241
+ if (typeof searchParams === 'string') {
242
+ if (path?.endsWith('/')) {
243
+ path = path.slice(0, -1)
244
+ }
245
+
246
+ path = `${path}?${searchParams}`
247
+ }
248
+ }
249
+
250
+ if (!path?.endsWith('/') && !params) {
251
+ path = path + '/'
252
+ }
253
+
254
+ this.to(path?.trim(), _options as O, {
255
+ params,
256
+ routeParams,
257
+ })
258
+ }
259
+
260
+ /**
261
+ * Calls the navigator to direct the user to a page
262
+ * @param path Path to which the user will be taken
263
+ * @param options Options that will be passed to the navigator
264
+ * @param info Information that will be added to the history
265
+ */
266
+ public to(path: RoutePath, options: O = null as O, info = {}) {
267
+ if (this.config.historyEnabled) {
268
+ this.putHistory(path, this.merge(options, info))
269
+ }
270
+
271
+ this.navigator(path, options)
272
+ }
273
+
274
+ /**
275
+ * Clear history data
276
+ */
277
+ public wipeHistory() {
278
+ this._history = {}
279
+ }
280
+ }
@@ -0,0 +1,54 @@
1
+
2
+ export type ExtractParams<T extends string> =
3
+ T extends `${infer _Start}{{${infer Param}}}${infer Rest}`
4
+ ? Param | ExtractParams<Rest>
5
+ : never
6
+
7
+ type Params<T> = {
8
+ [K in keyof T]: T[K] extends string ? ExtractParams<T[K]> : Params<T[K]>;
9
+ }
10
+
11
+ // @ts-ignore
12
+ type ExtractRoutes<T, PM, Prefix extends string = ''> = {
13
+ [K in keyof T & string]:
14
+ T[K] extends string
15
+ ? {
16
+ // @ts-ignore
17
+ [P in `${Prefix}${Prefix extends '' ? '' : '.'}${K}`]: PM[K]
18
+ } // @ts-ignore
19
+ : ExtractRoutes<T[K], PM[K], `${Prefix}${Prefix extends '' ? '' : '.'}${K}`>
20
+ }[keyof T]
21
+
22
+ type UnionToIntersection<U> =
23
+ (U extends any ? (x: U)=> void : never) extends ((x: infer I)=>void) ? I : never
24
+
25
+ export type Routes<T> = UnionToIntersection<ExtractRoutes<T, Params<T>>>
26
+
27
+ // Navigation types
28
+
29
+ export type RoutePath = string
30
+
31
+ export type RouteParams = {
32
+ [x: string]: string
33
+ }
34
+
35
+ export type Navigator<O extends object = {}> = (path: RoutePath, options: O) => void
36
+
37
+ export type AnyValue = {
38
+ [key: string]: any
39
+ }
40
+
41
+ export type HistoryData = {
42
+ origin: string
43
+ date: Date,
44
+ path: RoutePath,
45
+ metadata: any
46
+ info: any
47
+ }
48
+
49
+ export type History = Record<number, HistoryData>
50
+
51
+ export type Config = {
52
+ historyEnabled?: boolean
53
+ getMetadata?: () => any
54
+ }