@furystack/shades-common-components 3.2.2 → 3.4.0

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.
Files changed (114) hide show
  1. package/dist/components/animations.js +38 -20
  2. package/dist/components/animations.js.map +1 -1
  3. package/dist/components/button.js +2 -2
  4. package/dist/components/button.js.map +1 -1
  5. package/dist/components/command-palette/command-palette-manager.js +12 -5
  6. package/dist/components/command-palette/command-palette-manager.js.map +1 -1
  7. package/dist/components/command-palette/command-palette-suggestion-list.js +2 -4
  8. package/dist/components/command-palette/command-palette-suggestion-list.js.map +1 -1
  9. package/dist/components/command-palette/index.js +18 -5
  10. package/dist/components/command-palette/index.js.map +1 -1
  11. package/dist/components/data-grid/body.js +2 -3
  12. package/dist/components/data-grid/body.js.map +1 -1
  13. package/dist/components/data-grid/data-grid-row.js +20 -17
  14. package/dist/components/data-grid/data-grid-row.js.map +1 -1
  15. package/dist/components/data-grid/data-grid.js +4 -6
  16. package/dist/components/data-grid/data-grid.js.map +1 -1
  17. package/dist/components/data-grid/header.js +3 -5
  18. package/dist/components/data-grid/header.js.map +1 -1
  19. package/dist/components/data-grid/index.js +16 -3
  20. package/dist/components/data-grid/index.js.map +1 -1
  21. package/dist/components/grid.js +4 -9
  22. package/dist/components/grid.js.map +1 -1
  23. package/dist/components/index.js +32 -19
  24. package/dist/components/index.js.map +1 -1
  25. package/dist/components/{autocomplete.js → inputs/autocomplete.js} +1 -1
  26. package/dist/components/inputs/autocomplete.js.map +1 -0
  27. package/dist/components/inputs/index.js +20 -0
  28. package/dist/components/inputs/index.js.map +1 -0
  29. package/dist/components/inputs/input.js +112 -0
  30. package/dist/components/inputs/input.js.map +1 -0
  31. package/dist/components/inputs/text-area.js +76 -0
  32. package/dist/components/inputs/text-area.js.map +1 -0
  33. package/dist/components/modal.js +19 -3
  34. package/dist/components/modal.js.map +1 -1
  35. package/dist/components/noty-list.js +4 -5
  36. package/dist/components/noty-list.js.map +1 -1
  37. package/dist/components/paper.js +1 -1
  38. package/dist/components/paper.js.map +1 -1
  39. package/dist/components/suggest/index.js +18 -5
  40. package/dist/components/suggest/index.js.map +1 -1
  41. package/dist/components/suggest/suggest-manager.js +12 -5
  42. package/dist/components/suggest/suggest-manager.js.map +1 -1
  43. package/dist/components/suggest/suggestion-list.js +2 -4
  44. package/dist/components/suggest/suggestion-list.js.map +1 -1
  45. package/dist/components/wizard/index.js +36 -0
  46. package/dist/components/wizard/index.js.map +1 -0
  47. package/dist/index.js +17 -4
  48. package/dist/index.js.map +1 -1
  49. package/dist/services/collection-service.js +5 -3
  50. package/dist/services/collection-service.js.map +1 -1
  51. package/dist/services/index.js +21 -8
  52. package/dist/services/index.js.map +1 -1
  53. package/dist/services/noty-service.js +7 -2
  54. package/dist/services/noty-service.js.map +1 -1
  55. package/dist/services/theme-provider-service.js +27 -11
  56. package/dist/services/theme-provider-service.js.map +1 -1
  57. package/dist/utils/index.js +15 -2
  58. package/dist/utils/index.js.map +1 -1
  59. package/dist/utils/promisify-animation.js +6 -0
  60. package/dist/utils/promisify-animation.js.map +1 -1
  61. package/package.json +7 -8
  62. package/src/components/animations.ts +50 -28
  63. package/src/components/data-grid/body.tsx +8 -0
  64. package/src/components/data-grid/data-grid-row.tsx +22 -12
  65. package/src/components/data-grid/data-grid.tsx +38 -0
  66. package/src/components/data-grid/header.tsx +1 -1
  67. package/src/components/index.ts +2 -2
  68. package/src/components/{autocomplete.tsx → inputs/autocomplete.tsx} +3 -3
  69. package/src/components/inputs/index.ts +3 -0
  70. package/src/components/inputs/input.tsx +195 -0
  71. package/src/components/inputs/text-area.tsx +117 -0
  72. package/src/components/modal.tsx +30 -7
  73. package/src/components/noty-list.tsx +1 -1
  74. package/src/components/wizard/index.tsx +62 -0
  75. package/src/services/theme-provider-service.ts +21 -8
  76. package/src/utils/promisify-animation.ts +6 -0
  77. package/tsconfig.tsbuildinfo +1 -1
  78. package/types/components/animations.d.ts +5 -8
  79. package/types/components/animations.d.ts.map +1 -1
  80. package/types/components/app-bar-link.d.ts +3 -2
  81. package/types/components/app-bar-link.d.ts.map +1 -1
  82. package/types/components/data-grid/body.d.ts +4 -0
  83. package/types/components/data-grid/body.d.ts.map +1 -1
  84. package/types/components/data-grid/data-grid-row.d.ts +4 -0
  85. package/types/components/data-grid/data-grid-row.d.ts.map +1 -1
  86. package/types/components/data-grid/data-grid.d.ts +34 -0
  87. package/types/components/data-grid/data-grid.d.ts.map +1 -1
  88. package/types/components/fab.d.ts +3 -2
  89. package/types/components/fab.d.ts.map +1 -1
  90. package/types/components/index.d.ts +2 -2
  91. package/types/components/index.d.ts.map +1 -1
  92. package/types/components/{autocomplete.d.ts → inputs/autocomplete.d.ts} +3 -3
  93. package/types/components/inputs/autocomplete.d.ts.map +1 -0
  94. package/types/components/inputs/index.d.ts +4 -0
  95. package/types/components/inputs/index.d.ts.map +1 -0
  96. package/types/components/inputs/input.d.ts +54 -0
  97. package/types/components/inputs/input.d.ts.map +1 -0
  98. package/types/components/inputs/text-area.d.ts +14 -0
  99. package/types/components/inputs/text-area.d.ts.map +1 -0
  100. package/types/components/modal.d.ts +9 -4
  101. package/types/components/modal.d.ts.map +1 -1
  102. package/types/components/wizard/index.d.ts +14 -0
  103. package/types/components/wizard/index.d.ts.map +1 -0
  104. package/types/services/theme-provider-service.d.ts +10 -11
  105. package/types/services/theme-provider-service.d.ts.map +1 -1
  106. package/types/utils/promisify-animation.d.ts +6 -0
  107. package/types/utils/promisify-animation.d.ts.map +1 -1
  108. package/dist/components/autocomplete.js.map +0 -1
  109. package/dist/components/input.js +0 -89
  110. package/dist/components/input.js.map +0 -1
  111. package/src/components/input.tsx +0 -148
  112. package/types/components/autocomplete.d.ts.map +0 -1
  113. package/types/components/input.d.ts +0 -22
  114. package/types/components/input.d.ts.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { Shade, createComponent } from '@furystack/shades'
2
- import { Input, InputProps } from './input'
2
+ import { Input, TextInputProps } from './input'
3
3
 
4
4
  export const Autocomplete = Shade<
5
- { inputProps?: InputProps; suggestions: string[]; strict?: boolean; onchange: (value: string) => void },
5
+ { inputProps?: TextInputProps; suggestions: string[]; strict?: boolean; onchange?: (value: string) => void },
6
6
  { dataListId: string }
7
7
  >({
8
8
  getInitialState: () => ({
@@ -30,7 +30,7 @@ export const Autocomplete = Shade<
30
30
  return
31
31
  }
32
32
  }
33
- props.onchange(value)
33
+ props.onchange?.(value)
34
34
  }}
35
35
  />
36
36
  <datalist id={dataListId}>
@@ -0,0 +1,3 @@
1
+ export * from './autocomplete'
2
+ export * from './input'
3
+ export * from './text-area'
@@ -0,0 +1,195 @@
1
+ import { Shade, PartialElement, createComponent, attachStyles } from '@furystack/shades'
2
+ import { ThemeProviderService } from '../..'
3
+ import { Palette, Theme } from '../../services'
4
+
5
+ export interface TextInputProps extends PartialElement<HTMLInputElement> {
6
+ /**
7
+ * Callback that will be called when the input value changes
8
+ */
9
+ onTextChange?: (text: string) => void
10
+ /**
11
+ * An optional label title element or string
12
+ */
13
+ labelTitle?: JSX.Element | string
14
+
15
+ /**
16
+ * Optional props for the label element
17
+ */
18
+ labelProps?: PartialElement<HTMLLabelElement>
19
+
20
+ /**
21
+ * Boolean that indicates if the field will be focused automatically
22
+ */
23
+ autofocus?: boolean
24
+ /**
25
+ * The variant of the input
26
+ */
27
+ variant?: 'contained' | 'outlined'
28
+ /**
29
+ * The default color of the input (Error color will be used in case of invalid input value)
30
+ */
31
+ defaultColor?: keyof Palette
32
+ /**
33
+ * Optional callback for the helper text
34
+ */
35
+ getHelperText?: (options: { state: TextInputState }) => JSX.Element | string
36
+
37
+ /**
38
+ * Optional callback for retrieving an icon element on the left side of the input field
39
+ */
40
+ getStartIcon?: (options: { state: TextInputState }) => JSX.Element | string
41
+
42
+ /**
43
+ * Optional callback for retrieving an icon element on the right side of the input field
44
+ */
45
+ getEndIcon?: (options: { state: TextInputState }) => JSX.Element | string
46
+ }
47
+
48
+ export type TextInputState = {
49
+ theme: Theme
50
+ value: string
51
+ focused: boolean
52
+ validity: ValidityState
53
+ }
54
+
55
+ const getLabelStyle = ({
56
+ themeProvider,
57
+ props,
58
+ state,
59
+ }: {
60
+ themeProvider: ThemeProviderService
61
+ props: TextInputProps
62
+ state: TextInputState
63
+ }): Partial<CSSStyleDeclaration> => {
64
+ return {
65
+ display: 'flex',
66
+ flexDirection: 'column',
67
+ alignItems: 'flex-start',
68
+ justifyContent: 'space-between',
69
+ fontSize: '10px',
70
+ color: props.disabled
71
+ ? state.theme.text.disabled
72
+ : state.validity?.valid === false
73
+ ? state.theme.palette.error.main
74
+ : state.focused
75
+ ? state.theme.text.primary
76
+ : state.theme.text.secondary,
77
+ marginBottom: '1em',
78
+ padding: '1em',
79
+ borderRadius: '5px',
80
+ background:
81
+ props.variant === 'contained'
82
+ ? themeProvider
83
+ .getRgbFromColorString(
84
+ state.validity?.valid === false
85
+ ? state.theme.palette.error.main
86
+ : state.theme.palette[props.defaultColor || 'primary'].main,
87
+ )
88
+ .update('a', state.focused ? 0.1 : 0.2)
89
+ .toString()
90
+ : 'transparent',
91
+ boxShadow:
92
+ props.variant === 'outlined' || props.variant === 'contained'
93
+ ? `0 0 0 1px ${
94
+ state.validity?.valid === false
95
+ ? state.theme.palette.error.main
96
+ : state.focused
97
+ ? state.theme.palette[props.defaultColor || 'primary'].main
98
+ : state.theme.text.primary
99
+ }`
100
+ : 'none',
101
+ filter: props.disabled ? 'grayscale(100%)' : 'none',
102
+ opacity: props.disabled ? '0.5' : '1',
103
+ transition:
104
+ 'color 0.2s ease-in-out, filter 0.2s ease-in-out, opacity 0.2s ease-in-out, border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out',
105
+ ...props.labelProps?.style,
106
+ }
107
+ }
108
+
109
+ export const Input = Shade<TextInputProps, TextInputState>({
110
+ shadowDomName: 'shade-input',
111
+ getInitialState: ({ injector, props }) => ({
112
+ theme: injector.getInstance(ThemeProviderService).theme.getValue(),
113
+ value: props.value || '',
114
+ focused: props.autofocus || false,
115
+ validity: { valid: true } as ValidityState,
116
+ }),
117
+ resources: ({ injector, updateState }) => [
118
+ injector.getInstance(ThemeProviderService).theme.subscribe((theme) => updateState({ theme })),
119
+ ],
120
+ compareState: ({ newState, element, props, injector }) => {
121
+ const themeProvider = injector.getInstance(ThemeProviderService)
122
+ const label = element.querySelector('label') as HTMLLabelElement
123
+ attachStyles(label, { style: getLabelStyle({ themeProvider, props, state: newState }) })
124
+
125
+ const helper = element.querySelector<HTMLSpanElement>('span.helperText')
126
+ const helperNode = props.getHelperText?.({ state: newState }) || ''
127
+ helper?.replaceChildren(helperNode)
128
+
129
+ const startIcon = element.querySelector<HTMLSpanElement>('span.startIcon')
130
+ startIcon?.replaceChildren(props.getStartIcon?.({ state: newState }) || '')
131
+ const endIcon = element.querySelector<HTMLSpanElement>('span.endIcon')
132
+ endIcon?.replaceChildren(props.getEndIcon?.({ state: newState }) || '')
133
+
134
+ return false
135
+ },
136
+ render: ({ props, getState, updateState, injector }) => {
137
+ const state = getState()
138
+ const { value } = state
139
+ const themeProvider = injector.getInstance(ThemeProviderService)
140
+
141
+ return (
142
+ <label {...props.labelProps} style={getLabelStyle({ props, state, themeProvider })}>
143
+ {props.labelTitle}
144
+
145
+ <div
146
+ style={{
147
+ display: 'flex',
148
+ alignItems: 'center',
149
+ width: '100%',
150
+ }}
151
+ >
152
+ {props.getStartIcon ? <span className="startIcon">{props.getStartIcon?.({ state })}</span> : null}
153
+ <input
154
+ oninvalid={(ev) => {
155
+ ev.preventDefault()
156
+ const el = ev.target as HTMLInputElement
157
+ updateState({ validity: el.validity })
158
+ }}
159
+ onchange={(ev) => {
160
+ const el = ev.target as HTMLInputElement
161
+ const newValue = el.value
162
+ updateState({ value: newValue, validity: el?.validity })
163
+ props.onTextChange?.(newValue)
164
+ props.onchange && (props.onchange as any)(ev)
165
+ }}
166
+ onfocus={() => {
167
+ updateState({ focused: true })
168
+ }}
169
+ onblur={() => {
170
+ updateState({ focused: false })
171
+ }}
172
+ {...props}
173
+ style={{
174
+ color: 'inherit',
175
+ border: 'none',
176
+ backgroundColor: 'transparent',
177
+ outline: 'none',
178
+ fontSize: '12px',
179
+ width: '100%',
180
+ textOverflow: 'ellipsis',
181
+ padding: '0',
182
+ marginTop: '0.6em',
183
+ marginBottom: '0.4em',
184
+ flexGrow: '1',
185
+ ...props.style,
186
+ }}
187
+ value={value}
188
+ />
189
+ {props.getEndIcon ? <span className="endIcon">{props.getEndIcon({ state })}</span> : null}
190
+ </div>
191
+ <span className="helperText">{props.getHelperText?.({ state })}</span>
192
+ </label>
193
+ )
194
+ },
195
+ })
@@ -0,0 +1,117 @@
1
+ import { createComponent, PartialElement, Shade } from '@furystack/shades'
2
+ import { Theme, ThemeProviderService } from '../../services'
3
+ import { promisifyAnimation } from '../../utils'
4
+
5
+ export interface TextAreaProps extends PartialElement<HTMLTextAreaElement> {
6
+ labelTitle?: string
7
+ labelProps?: PartialElement<HTMLLabelElement>
8
+ autofocus?: boolean
9
+ variant?: 'contained' | 'outlined'
10
+ }
11
+
12
+ export type TextAreaInputState = {
13
+ theme: Theme
14
+ value?: string
15
+ }
16
+
17
+ export const TextArea = Shade<TextAreaProps, TextAreaInputState>({
18
+ shadowDomName: 'shade-text-area',
19
+ getInitialState: ({ injector, props }) => ({
20
+ theme: injector.getInstance(ThemeProviderService).theme.getValue(),
21
+ value: props.value,
22
+ }),
23
+ resources: ({ injector, updateState }) => {
24
+ const themeProvider = injector.getInstance(ThemeProviderService)
25
+ return [themeProvider.theme.subscribe((theme) => updateState({ theme }))]
26
+ },
27
+ render: ({ props, element, injector, getState }) => {
28
+ const themeProvider = injector.getInstance(ThemeProviderService)
29
+ const { theme, value } = getState()
30
+ const { palette } = theme
31
+
32
+ return (
33
+ <label
34
+ {...props.labelProps}
35
+ style={{
36
+ display: 'flex',
37
+ flexDirection: 'column',
38
+ alignItems: 'flex-start',
39
+ justifyContent: 'space-between',
40
+ fontSize: '10px',
41
+ color: props.disabled ? 'rgb(170, 170, 170)' : '#bbb',
42
+ marginBottom: '1em',
43
+ padding: '1em',
44
+ borderRadius: '5px',
45
+ border: props.variant === 'outlined' ? '1px solid #bbb' : 'none',
46
+ ...props.labelProps?.style,
47
+ }}
48
+ >
49
+ <span>{props.labelTitle}</span>
50
+
51
+ <div
52
+ contentEditable={props.readOnly === true || props.disabled === true ? 'inherit' : 'true'}
53
+ {...props}
54
+ style={{
55
+ border: 'none',
56
+ backgroundColor: 'transparent',
57
+ outline: 'none',
58
+ fontSize: '12px',
59
+ width: '100%',
60
+ textOverflow: 'ellipsis',
61
+ ...props.style,
62
+ }}
63
+ onfocus={() => {
64
+ if (!props.disabled) {
65
+ promisifyAnimation(
66
+ element.querySelector('label'),
67
+ [{ color: themeProvider.getTextColor(theme.background.default) }, { color: palette.primary.main }],
68
+ {
69
+ duration: 500,
70
+ easing: 'cubic-bezier(0.455, 0.030, 0.515, 0.955)',
71
+ fill: 'forwards',
72
+ },
73
+ )
74
+ promisifyAnimation(
75
+ element.querySelector('div[contenteditable="true"]'),
76
+ [
77
+ { boxShadow: '0px 0px 0px rgba(128,128,128,0.1)' },
78
+ { boxShadow: `0px 3px 0px ${palette.primary.main}` },
79
+ ],
80
+ {
81
+ duration: 200,
82
+ fill: 'forwards',
83
+ },
84
+ )
85
+ }
86
+ }}
87
+ onblur={() => {
88
+ if (!props.disabled) {
89
+ promisifyAnimation(
90
+ element.querySelector('label'),
91
+ [{ color: palette.primary.main }, { color: themeProvider.getTextColor(theme.background.default) }],
92
+ {
93
+ duration: 200,
94
+ easing: 'cubic-bezier(0.455, 0.030, 0.515, 0.955)',
95
+ fill: 'forwards',
96
+ },
97
+ )
98
+ promisifyAnimation(
99
+ element.querySelector('div[contenteditable="true"]'),
100
+ [
101
+ { boxShadow: '0px 3px 0px rgba(128,128,128,0.4)' },
102
+ { boxShadow: '0px 0px 0px rgba(128,128,128,0.1)' },
103
+ ],
104
+ {
105
+ duration: 400,
106
+ fill: 'forwards',
107
+ },
108
+ )
109
+ }
110
+ }}
111
+ >
112
+ {value}
113
+ </div>
114
+ </label>
115
+ )
116
+ },
117
+ })
@@ -1,12 +1,36 @@
1
1
  import { Shade, createComponent } from '@furystack/shades'
2
+ import { ObservableValue } from '@furystack/utils'
2
3
 
3
- export const Modal = Shade<{ isVisible: boolean; onClose?: () => void }>({
4
+ export type ModalProps = {
5
+ backdropStyle?: Partial<CSSStyleDeclaration>
6
+ isVisible: ObservableValue<boolean>
7
+ onClose?: () => void
8
+ showAnimation?: (el: Element | null) => Promise<void>
9
+ hideAnimation?: (el: Element | null) => Promise<void>
10
+ }
11
+
12
+ export const Modal = Shade<ModalProps, { isVisible?: boolean }>({
13
+ getInitialState: ({ props }) => ({ isVisible: props.isVisible.getValue() }),
4
14
  shadowDomName: 'shade-modal',
5
- render: ({ props, children }) => {
6
- return props.isVisible ? (
15
+ resources: ({ props, element, updateState }) => [
16
+ props.isVisible.subscribe(async (visible) => {
17
+ if (visible) {
18
+ updateState({ isVisible: visible })
19
+ await props.showAnimation?.(element)
20
+ } else {
21
+ await props.hideAnimation?.(element).finally(() => updateState({ isVisible: visible }))
22
+ }
23
+ }),
24
+ ],
25
+
26
+ render: ({ props, getState, children }) => {
27
+ const { isVisible } = getState()
28
+ return isVisible ? (
7
29
  <div
8
30
  className="shade-backdrop"
9
- onclick={() => props.onClose?.()}
31
+ onclick={() => {
32
+ props.onClose?.()
33
+ }}
10
34
  style={{
11
35
  width: '100%',
12
36
  height: '100%',
@@ -14,12 +38,11 @@ export const Modal = Shade<{ isVisible: boolean; onClose?: () => void }>({
14
38
  position: 'fixed',
15
39
  top: '0',
16
40
  left: '0',
41
+ ...props.backdropStyle,
17
42
  }}
18
43
  >
19
44
  {children}
20
45
  </div>
21
- ) : (
22
- <div />
23
- )
46
+ ) : null
24
47
  },
25
48
  })
@@ -131,7 +131,7 @@ export const NotyList = Shade<unknown, { currentNotys: NotyModel[] }>({
131
131
  }),
132
132
  notyService.onNotyRemoved.subscribe((n) => {
133
133
  element.querySelectorAll('shade-noty').forEach((e) => {
134
- if ((e as any).props.getValue().model === n) {
134
+ if ((e as JSX.Element).props.model === n) {
135
135
  e.remove()
136
136
  }
137
137
  })
@@ -0,0 +1,62 @@
1
+ import { ChildrenList, createComponent, Shade } from '@furystack/shades'
2
+ import { Paper } from '../paper'
3
+
4
+ export interface WizardStepProps {
5
+ currentPage: number
6
+ maxPages: number
7
+ onNext?: () => void
8
+ onPrev?: () => void
9
+ }
10
+
11
+ export interface WizardProps {
12
+ steps: Array<(props: WizardStepProps, children: ChildrenList) => JSX.Element<any, any>>
13
+ isOpened?: boolean
14
+ onFinish?: () => void
15
+ }
16
+
17
+ interface WizardState {
18
+ currentPage: number
19
+ }
20
+
21
+ export const Wizard = Shade<WizardProps, WizardState>({
22
+ shadowDomName: 'shades-wizard',
23
+ getInitialState: () => ({
24
+ currentPage: 0,
25
+ }),
26
+ render: ({ props, getState, updateState }) => {
27
+ const { currentPage } = getState()
28
+
29
+ const CurrentPage = props.steps[currentPage]
30
+
31
+ return (
32
+ <div
33
+ style={{
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ justifyContent: 'center',
37
+ width: '100%',
38
+ height: '100%',
39
+ }}
40
+ >
41
+ <Paper elevation={3} onclick={(ev) => ev.stopPropagation()}>
42
+ <CurrentPage
43
+ currentPage={currentPage}
44
+ maxPages={props.steps.length}
45
+ onNext={() => {
46
+ if (currentPage < props.steps.length - 1) {
47
+ updateState({ currentPage: currentPage + 1 })
48
+ } else {
49
+ props.onFinish?.()
50
+ }
51
+ }}
52
+ onPrev={() => {
53
+ if (currentPage > 0) {
54
+ updateState({ currentPage: currentPage - 1 })
55
+ }
56
+ }}
57
+ />
58
+ </Paper>
59
+ </div>
60
+ )
61
+ },
62
+ })
@@ -46,6 +46,19 @@ export interface Theme {
46
46
  divider: Color
47
47
  }
48
48
 
49
+ export class RgbColor {
50
+ constructor(public r: number, public g: number, public b: number, public a: number = 1) {}
51
+
52
+ public update(key: 'r' | 'g' | 'b' | 'a', value: number): RgbColor {
53
+ this[key] = value
54
+ return this
55
+ }
56
+
57
+ public toString(): string {
58
+ return `rgba(${this.r},${this.g},${this.b},${this.a})`
59
+ }
60
+ }
61
+
49
62
  /**
50
63
  * Service class for theme-related operations
51
64
  */
@@ -75,13 +88,13 @@ export class ThemeProviderService {
75
88
  const r = parseInt(color.substr(1, 2), 16)
76
89
  const g = parseInt(color.substr(3, 2), 16)
77
90
  const b = parseInt(color.substr(5, 2), 16)
78
- return { r, g, b }
91
+ return new RgbColor(r, g, b)
79
92
  }
80
93
  if (color.length === 4) {
81
94
  const r = parseInt(color.substr(1, 1) + color.substr(1, 1), 16)
82
95
  const g = parseInt(color.substr(2, 1) + color.substr(2, 1), 16)
83
96
  const b = parseInt(color.substr(3, 1) + color.substr(3, 1), 16)
84
- return { r, g, b }
97
+ return new RgbColor(r, g, b)
85
98
  }
86
99
  }
87
100
  if (color.startsWith('rgba(')) {
@@ -89,12 +102,12 @@ export class ThemeProviderService {
89
102
  /^rgba[(](?<red>[\d]+)[,][\s]?(?<green>[\d]+)[,][\s]?(?<blue>[\d]+)[,][\s]?(?<alpha>[\d|.]+)[)]/gm,
90
103
  ).exec(color)
91
104
  if (result && result.groups) {
92
- return {
93
- r: parseInt(result.groups.red, 10),
94
- g: parseInt(result.groups.green, 10),
95
- b: parseInt(result.groups.blue, 10),
96
- a: parseInt(result.groups.alpha, 10),
97
- }
105
+ return new RgbColor(
106
+ parseInt(result.groups.red, 10),
107
+ parseInt(result.groups.green, 10),
108
+ parseInt(result.groups.blue, 10),
109
+ parseInt(result.groups.alpha, 10),
110
+ )
98
111
  }
99
112
  }
100
113
  throw Error(`Color format '${color} is not supported.'`)
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @param el The element to animate
3
+ * @param keyframes A list of keyframe definitions
4
+ * @param options Animation options
5
+ * @returns A promise that resolves when the animation is complete or rejects if cancelled
6
+ */
1
7
  export const promisifyAnimation = async (
2
8
  el: Element | null,
3
9
  keyframes: Keyframe[] | PropertyIndexedKeyframes | null,