shadcn_phlexcomponents 0.1.11 → 0.1.14
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.
- checksums.yaml +4 -4
- data/app/javascript/controllers/accordion_controller.ts +65 -62
- data/app/javascript/controllers/alert_dialog_controller.ts +12 -0
- data/app/javascript/controllers/avatar_controller.ts +7 -2
- data/app/javascript/controllers/checkbox_controller.ts +11 -4
- data/app/javascript/controllers/collapsible_controller.ts +12 -5
- data/app/javascript/controllers/combobox_controller.ts +270 -39
- data/app/javascript/controllers/command_controller.ts +223 -51
- data/app/javascript/controllers/date_picker_controller.ts +185 -125
- data/app/javascript/controllers/date_range_picker_controller.ts +89 -79
- data/app/javascript/controllers/dialog_controller.ts +59 -57
- data/app/javascript/controllers/dropdown_menu_controller.ts +212 -36
- data/app/javascript/controllers/dropdown_menu_sub_controller.ts +31 -29
- data/app/javascript/controllers/form_field_controller.ts +6 -1
- data/app/javascript/controllers/hover_card_controller.ts +36 -26
- data/app/javascript/controllers/loading_button_controller.ts +6 -1
- data/app/javascript/controllers/popover_controller.ts +42 -65
- data/app/javascript/controllers/progress_controller.ts +9 -3
- data/app/javascript/controllers/radio_group_controller.ts +16 -9
- data/app/javascript/controllers/select_controller.ts +206 -65
- data/app/javascript/controllers/slider_controller.ts +23 -16
- data/app/javascript/controllers/switch_controller.ts +11 -4
- data/app/javascript/controllers/tabs_controller.ts +26 -18
- data/app/javascript/controllers/theme_switcher_controller.ts +6 -1
- data/app/javascript/controllers/toast_container_controller.ts +6 -1
- data/app/javascript/controllers/toast_controller.ts +7 -1
- data/app/javascript/controllers/toggle_controller.ts +28 -0
- data/app/javascript/controllers/toggle_group_controller.ts +28 -0
- data/app/javascript/controllers/tooltip_controller.ts +43 -31
- data/app/javascript/shadcn_phlexcomponents.ts +29 -25
- data/app/javascript/utils/command.ts +544 -0
- data/app/javascript/utils/floating_ui.ts +196 -0
- data/app/javascript/utils/index.ts +417 -0
- data/app/stylesheets/date_picker.css +118 -0
- data/lib/shadcn_phlexcomponents/alias.rb +3 -0
- data/lib/shadcn_phlexcomponents/components/accordion.rb +2 -1
- data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +18 -15
- data/lib/shadcn_phlexcomponents/components/base.rb +14 -0
- data/lib/shadcn_phlexcomponents/components/collapsible.rb +1 -2
- data/lib/shadcn_phlexcomponents/components/combobox.rb +87 -57
- data/lib/shadcn_phlexcomponents/components/command.rb +77 -47
- data/lib/shadcn_phlexcomponents/components/date_picker.rb +25 -81
- data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +21 -4
- data/lib/shadcn_phlexcomponents/components/dialog.rb +14 -12
- data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +5 -4
- data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +2 -1
- data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +64 -0
- data/lib/shadcn_phlexcomponents/components/form.rb +14 -0
- data/lib/shadcn_phlexcomponents/components/hover_card.rb +3 -2
- data/lib/shadcn_phlexcomponents/components/popover.rb +3 -3
- data/lib/shadcn_phlexcomponents/components/select.rb +10 -25
- data/lib/shadcn_phlexcomponents/components/sheet.rb +15 -11
- data/lib/shadcn_phlexcomponents/components/table.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/tabs.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/toast_container.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/toggle.rb +54 -0
- data/lib/shadcn_phlexcomponents/components/tooltip.rb +3 -2
- data/lib/shadcn_phlexcomponents/engine.rb +1 -5
- data/lib/shadcn_phlexcomponents/version.rb +1 -1
- metadata +9 -4
- data/app/javascript/controllers/command_root_controller.ts +0 -355
- data/app/javascript/controllers/dropdown_menu_root_controller.ts +0 -234
- data/app/javascript/utils.ts +0 -437
data/app/javascript/utils.ts
DELETED
@@ -1,437 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
computePosition,
|
3
|
-
flip,
|
4
|
-
shift,
|
5
|
-
offset,
|
6
|
-
autoUpdate,
|
7
|
-
size,
|
8
|
-
Placement,
|
9
|
-
Middleware,
|
10
|
-
arrow,
|
11
|
-
} from '@floating-ui/dom'
|
12
|
-
|
13
|
-
const ANIMATION_OUT_DELAY = 100
|
14
|
-
const ON_OPEN_FOCUS_DELAY = 100
|
15
|
-
const ON_CLOSE_FOCUS_DELAY = 50
|
16
|
-
|
17
|
-
const OPPOSITE_SIDE = {
|
18
|
-
top: 'bottom',
|
19
|
-
right: 'left',
|
20
|
-
bottom: 'top',
|
21
|
-
left: 'right',
|
22
|
-
}
|
23
|
-
|
24
|
-
const ARROW_TRANSFORM_ORIGIN = {
|
25
|
-
top: '',
|
26
|
-
right: '0 0',
|
27
|
-
bottom: 'center 0',
|
28
|
-
left: '100% 0',
|
29
|
-
}
|
30
|
-
|
31
|
-
const ARROW_TRANSFORM = {
|
32
|
-
top: 'translateY(100%)',
|
33
|
-
right: 'translateY(50%) rotate(90deg) translateX(-50%)',
|
34
|
-
bottom: `rotate(180deg)`,
|
35
|
-
left: 'translateY(50%) rotate(-90deg) translateX(50%)',
|
36
|
-
}
|
37
|
-
|
38
|
-
const getScrollbarWidth = () => {
|
39
|
-
// Create a temporary div container and append it into the body
|
40
|
-
const outer = document.createElement('div')
|
41
|
-
outer.style.visibility = 'hidden'
|
42
|
-
outer.style.overflow = 'scroll' // force scrollbars
|
43
|
-
outer.style.width = '100px'
|
44
|
-
outer.style.position = 'absolute'
|
45
|
-
outer.style.top = '-9999px'
|
46
|
-
document.body.appendChild(outer)
|
47
|
-
|
48
|
-
// Create an inner div and place it inside the outer div
|
49
|
-
const inner = document.createElement('div')
|
50
|
-
inner.style.width = '100%'
|
51
|
-
outer.appendChild(inner)
|
52
|
-
|
53
|
-
// Calculate the scrollbar width
|
54
|
-
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth
|
55
|
-
|
56
|
-
// Clean up
|
57
|
-
outer.remove()
|
58
|
-
|
59
|
-
return scrollbarWidth
|
60
|
-
}
|
61
|
-
|
62
|
-
const showOverlay = ({
|
63
|
-
classNames = '',
|
64
|
-
elementId,
|
65
|
-
}: {
|
66
|
-
classNames?: string
|
67
|
-
elementId: string
|
68
|
-
}) => {
|
69
|
-
const element = document.createElement('div')
|
70
|
-
|
71
|
-
let defaultClassNames = [
|
72
|
-
'data-[state=open]:animate-in',
|
73
|
-
'data-[state=closed]:animate-out',
|
74
|
-
'data-[state=closed]:fade-out-0',
|
75
|
-
'data-[state=open]:fade-in-0',
|
76
|
-
'fixed',
|
77
|
-
'inset-0',
|
78
|
-
'z-[48]',
|
79
|
-
'bg-black/50',
|
80
|
-
'pointer-events-auto',
|
81
|
-
]
|
82
|
-
|
83
|
-
defaultClassNames = defaultClassNames.concat(
|
84
|
-
classNames.split(' ').filter((c) => !!c),
|
85
|
-
)
|
86
|
-
|
87
|
-
element.classList.add(...defaultClassNames)
|
88
|
-
element.dataset.state = 'open'
|
89
|
-
element.dataset.shadcnPhlexcomponentsOverlay = elementId
|
90
|
-
element.ariaHidden = 'true'
|
91
|
-
|
92
|
-
document.body.appendChild(element)
|
93
|
-
}
|
94
|
-
|
95
|
-
const hideOverlay = (elementId: string) => {
|
96
|
-
const element = document.querySelector(
|
97
|
-
`[data-shadcn-phlexcomponents-overlay=${elementId}]`,
|
98
|
-
)
|
99
|
-
|
100
|
-
if (element && element instanceof HTMLElement) {
|
101
|
-
element.dataset.state = 'closed'
|
102
|
-
|
103
|
-
setTimeout(() => {
|
104
|
-
element.remove()
|
105
|
-
}, ANIMATION_OUT_DELAY)
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
const lockScroll = () => {
|
110
|
-
if (window.innerHeight < document.documentElement.scrollHeight) {
|
111
|
-
document.body.dataset.scrollLocked = '1'
|
112
|
-
document.body.classList.add(
|
113
|
-
'data-[scroll-locked]:pointer-events-none',
|
114
|
-
'data-[scroll-locked]:!overflow-hidden',
|
115
|
-
'data-[scroll-locked]:!relative',
|
116
|
-
'data-[scroll-locked]:px-0',
|
117
|
-
'data-[scroll-locked]:pt-0',
|
118
|
-
'data-[scroll-locked]:ml-0',
|
119
|
-
'data-[scroll-locked]:mt-0',
|
120
|
-
)
|
121
|
-
const style = getComputedStyle(document.body)
|
122
|
-
const originalMarginRight = style.marginRight
|
123
|
-
document.body.dataset.marginRight = originalMarginRight
|
124
|
-
document.body.style.marginRight = `${getScrollbarWidth()}px`
|
125
|
-
}
|
126
|
-
}
|
127
|
-
|
128
|
-
const unlockScroll = () => {
|
129
|
-
if (document.body.dataset.scrollLocked) {
|
130
|
-
delete document.body.dataset.scrollLocked
|
131
|
-
document.body.classList.remove(
|
132
|
-
'data-[scroll-locked]:pointer-events-none',
|
133
|
-
'data-[scroll-locked]:!overflow-hidden',
|
134
|
-
'data-[scroll-locked]:!relative',
|
135
|
-
'data-[scroll-locked]:px-0',
|
136
|
-
'data-[scroll-locked]:pt-0',
|
137
|
-
'data-[scroll-locked]:ml-0',
|
138
|
-
'data-[scroll-locked]:mt-0',
|
139
|
-
)
|
140
|
-
|
141
|
-
const originalMarginRight = document.body.dataset.marginRight
|
142
|
-
|
143
|
-
if (originalMarginRight && parseInt(originalMarginRight) === 0) {
|
144
|
-
document.body.style.marginRight = ''
|
145
|
-
} else {
|
146
|
-
document.body.style.marginRight = `${originalMarginRight}`
|
147
|
-
}
|
148
|
-
|
149
|
-
delete document.body.dataset.marginRight
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
const openWithOverlay = (elementId: string) => {
|
154
|
-
showOverlay({ elementId })
|
155
|
-
lockScroll()
|
156
|
-
}
|
157
|
-
|
158
|
-
const closeWithOverlay = (elementId: string) => {
|
159
|
-
hideOverlay(elementId)
|
160
|
-
unlockScroll()
|
161
|
-
}
|
162
|
-
|
163
|
-
const initFloatingUi = ({
|
164
|
-
referenceElement,
|
165
|
-
floatingElement,
|
166
|
-
side = 'bottom',
|
167
|
-
align = 'center',
|
168
|
-
sideOffset = 0,
|
169
|
-
alignOffset = 0,
|
170
|
-
arrowElement,
|
171
|
-
}: {
|
172
|
-
referenceElement: HTMLElement
|
173
|
-
floatingElement: HTMLElement
|
174
|
-
side?: string
|
175
|
-
align?: string
|
176
|
-
sideOffset?: number
|
177
|
-
alignOffset?: number
|
178
|
-
offsetPx?: number
|
179
|
-
arrowElement?: HTMLElement
|
180
|
-
}) => {
|
181
|
-
let placement = `${side}-${align}`
|
182
|
-
placement = placement.replace(/-center/g, '')
|
183
|
-
|
184
|
-
let arrowHeight = 0,
|
185
|
-
arrowWidth = 0
|
186
|
-
|
187
|
-
if (arrowElement) {
|
188
|
-
const rect = arrowElement.getBoundingClientRect()
|
189
|
-
arrowWidth = rect.width
|
190
|
-
arrowHeight = rect.height
|
191
|
-
}
|
192
|
-
|
193
|
-
const middleware = [
|
194
|
-
transformOrigin({ arrowHeight, arrowWidth }),
|
195
|
-
offset({ mainAxis: sideOffset, alignmentAxis: alignOffset }),
|
196
|
-
size({
|
197
|
-
apply: ({ elements, rects, availableWidth, availableHeight }) => {
|
198
|
-
const { width: anchorWidth, height: anchorHeight } = rects.reference
|
199
|
-
const contentStyle = elements.floating.style
|
200
|
-
contentStyle.setProperty(
|
201
|
-
'--radix-popper-available-width',
|
202
|
-
`${availableWidth}px`,
|
203
|
-
)
|
204
|
-
contentStyle.setProperty(
|
205
|
-
'--radix-popper-available-height',
|
206
|
-
`${availableHeight}px`,
|
207
|
-
)
|
208
|
-
contentStyle.setProperty(
|
209
|
-
'--radix-popper-anchor-width',
|
210
|
-
`${anchorWidth}px`,
|
211
|
-
)
|
212
|
-
contentStyle.setProperty(
|
213
|
-
'--radix-popper-anchor-height',
|
214
|
-
`${anchorHeight}px`,
|
215
|
-
)
|
216
|
-
},
|
217
|
-
}),
|
218
|
-
]
|
219
|
-
|
220
|
-
const flipMiddleware = flip({
|
221
|
-
// Ensure we flip to the perpendicular axis if it doesn't fit
|
222
|
-
// on narrow viewports.
|
223
|
-
crossAxis: 'alignment',
|
224
|
-
fallbackAxisSideDirection: 'end', // or 'start'
|
225
|
-
})
|
226
|
-
const shiftMiddleware = shift()
|
227
|
-
|
228
|
-
// Prioritize flip over shift for edge-aligned placements only.
|
229
|
-
if (placement.includes('-')) {
|
230
|
-
middleware.push(flipMiddleware, shiftMiddleware)
|
231
|
-
} else {
|
232
|
-
middleware.push(shiftMiddleware, flipMiddleware)
|
233
|
-
}
|
234
|
-
|
235
|
-
if (arrowElement) {
|
236
|
-
middleware.push(arrow({ element: arrowElement, padding: 0 }))
|
237
|
-
}
|
238
|
-
|
239
|
-
return autoUpdate(referenceElement, floatingElement, () => {
|
240
|
-
computePosition(referenceElement, floatingElement, {
|
241
|
-
placement: placement as Placement,
|
242
|
-
strategy: 'fixed',
|
243
|
-
middleware,
|
244
|
-
}).then(({ middlewareData, x, y }) => {
|
245
|
-
const arrowX = middlewareData.arrow?.x
|
246
|
-
const arrowY = middlewareData.arrow?.y
|
247
|
-
const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0
|
248
|
-
|
249
|
-
floatingElement.style.setProperty(
|
250
|
-
'--radix-popper-transform-origin',
|
251
|
-
`${middlewareData.transformOrigin?.x} ${middlewareData.transformOrigin?.y}`,
|
252
|
-
)
|
253
|
-
if (arrowElement) {
|
254
|
-
const baseSide = OPPOSITE_SIDE[side as keyof typeof OPPOSITE_SIDE]
|
255
|
-
|
256
|
-
const arrowStyle = {
|
257
|
-
position: 'absolute',
|
258
|
-
left: arrowX ? `${arrowX}px` : undefined,
|
259
|
-
top: arrowY ? `${arrowY}px` : undefined,
|
260
|
-
[baseSide]: 0,
|
261
|
-
transformOrigin:
|
262
|
-
ARROW_TRANSFORM_ORIGIN[side as keyof typeof ARROW_TRANSFORM_ORIGIN],
|
263
|
-
transform: ARROW_TRANSFORM[side as keyof typeof ARROW_TRANSFORM],
|
264
|
-
visibility: cannotCenterArrow ? 'hidden' : undefined,
|
265
|
-
}
|
266
|
-
|
267
|
-
Object.assign(arrowElement.style, arrowStyle)
|
268
|
-
}
|
269
|
-
Object.assign(floatingElement.style, {
|
270
|
-
left: `${x}px`,
|
271
|
-
top: `${y}px`,
|
272
|
-
})
|
273
|
-
})
|
274
|
-
})
|
275
|
-
}
|
276
|
-
|
277
|
-
const transformOrigin = (options: {
|
278
|
-
arrowWidth: number
|
279
|
-
arrowHeight: number
|
280
|
-
}): Middleware => {
|
281
|
-
return {
|
282
|
-
name: 'transformOrigin',
|
283
|
-
options,
|
284
|
-
fn(data) {
|
285
|
-
const { placement, rects, middlewareData } = data
|
286
|
-
const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0
|
287
|
-
const isArrowHidden = cannotCenterArrow
|
288
|
-
const arrowWidth = isArrowHidden ? 0 : options.arrowWidth
|
289
|
-
const arrowHeight = isArrowHidden ? 0 : options.arrowHeight
|
290
|
-
|
291
|
-
const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement)
|
292
|
-
const noArrowAlign = { start: '0%', center: '50%', end: '100%' }[
|
293
|
-
placedAlign
|
294
|
-
] as string
|
295
|
-
|
296
|
-
const arrowXCenter = (middlewareData.arrow?.x ?? 0) + arrowWidth / 2
|
297
|
-
const arrowYCenter = (middlewareData.arrow?.y ?? 0) + arrowHeight / 2
|
298
|
-
|
299
|
-
let x = ''
|
300
|
-
let y = ''
|
301
|
-
|
302
|
-
if (placedSide === 'bottom') {
|
303
|
-
x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`
|
304
|
-
y = `${-arrowHeight}px`
|
305
|
-
} else if (placedSide === 'top') {
|
306
|
-
x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`
|
307
|
-
y = `${rects.floating.height + arrowHeight}px`
|
308
|
-
} else if (placedSide === 'right') {
|
309
|
-
x = `${-arrowHeight}px`
|
310
|
-
y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`
|
311
|
-
} else if (placedSide === 'left') {
|
312
|
-
x = `${rects.floating.width + arrowHeight}px`
|
313
|
-
y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`
|
314
|
-
}
|
315
|
-
return { data: { x, y } }
|
316
|
-
},
|
317
|
-
}
|
318
|
-
}
|
319
|
-
|
320
|
-
function getSideAndAlignFromPlacement(placement: Placement) {
|
321
|
-
const [side, align = 'center'] = placement.split('-')
|
322
|
-
return [side, align] as const
|
323
|
-
}
|
324
|
-
|
325
|
-
const focusTrigger = (triggerTarget: HTMLElement) => {
|
326
|
-
setTimeout(() => {
|
327
|
-
if (triggerTarget.dataset.asChild === 'false') {
|
328
|
-
const childElement = triggerTarget.firstElementChild as HTMLElement
|
329
|
-
|
330
|
-
if (childElement) {
|
331
|
-
childElement.focus()
|
332
|
-
}
|
333
|
-
} else {
|
334
|
-
triggerTarget.focus()
|
335
|
-
}
|
336
|
-
}, ON_CLOSE_FOCUS_DELAY)
|
337
|
-
}
|
338
|
-
|
339
|
-
const getFocusableElements = (container: HTMLElement) => {
|
340
|
-
return Array.from(
|
341
|
-
container.querySelectorAll(
|
342
|
-
'button, [href], input:not([type="hidden"]), select:not([tabindex="-1"]), textarea, [tabindex]:not([tabindex="-1"])',
|
343
|
-
),
|
344
|
-
) as HTMLElement[]
|
345
|
-
}
|
346
|
-
|
347
|
-
const getSameLevelItems = ({
|
348
|
-
content,
|
349
|
-
items,
|
350
|
-
closestContentSelector,
|
351
|
-
}: {
|
352
|
-
content: HTMLElement
|
353
|
-
items: HTMLElement[]
|
354
|
-
closestContentSelector: string
|
355
|
-
}) => {
|
356
|
-
let sameLevelItems = [] as HTMLElement[]
|
357
|
-
|
358
|
-
items.forEach((i) => {
|
359
|
-
if (
|
360
|
-
i.closest(closestContentSelector) === content &&
|
361
|
-
i.dataset.disabled === undefined
|
362
|
-
) {
|
363
|
-
sameLevelItems.push(i)
|
364
|
-
}
|
365
|
-
})
|
366
|
-
|
367
|
-
return sameLevelItems
|
368
|
-
}
|
369
|
-
|
370
|
-
const showContent = ({
|
371
|
-
trigger,
|
372
|
-
content,
|
373
|
-
contentContainer,
|
374
|
-
setEqualWidth,
|
375
|
-
}: {
|
376
|
-
trigger?: HTMLElement
|
377
|
-
content: HTMLElement
|
378
|
-
contentContainer: HTMLElement
|
379
|
-
setEqualWidth?: boolean
|
380
|
-
}) => {
|
381
|
-
contentContainer.classList.remove('hidden')
|
382
|
-
|
383
|
-
if (trigger) {
|
384
|
-
if (setEqualWidth) {
|
385
|
-
const triggerWidth = trigger.offsetWidth
|
386
|
-
const contentContainerWidth = contentContainer.offsetWidth
|
387
|
-
|
388
|
-
if (contentContainerWidth < triggerWidth) {
|
389
|
-
contentContainer.style.width = `${triggerWidth}px`
|
390
|
-
}
|
391
|
-
}
|
392
|
-
|
393
|
-
trigger.ariaExpanded = 'true'
|
394
|
-
trigger.dataset.state = 'open'
|
395
|
-
}
|
396
|
-
|
397
|
-
content.dataset.state = 'open'
|
398
|
-
}
|
399
|
-
|
400
|
-
const hideContent = ({
|
401
|
-
trigger,
|
402
|
-
content,
|
403
|
-
contentContainer,
|
404
|
-
}: {
|
405
|
-
trigger?: HTMLElement
|
406
|
-
content: HTMLElement
|
407
|
-
contentContainer: HTMLElement
|
408
|
-
}) => {
|
409
|
-
if (trigger) {
|
410
|
-
trigger.ariaExpanded = 'false'
|
411
|
-
trigger.dataset.state = 'closed'
|
412
|
-
}
|
413
|
-
|
414
|
-
content.dataset.state = 'closed'
|
415
|
-
|
416
|
-
setTimeout(() => {
|
417
|
-
contentContainer.classList.add('hidden')
|
418
|
-
}, ANIMATION_OUT_DELAY)
|
419
|
-
}
|
420
|
-
|
421
|
-
export {
|
422
|
-
ANIMATION_OUT_DELAY,
|
423
|
-
ON_CLOSE_FOCUS_DELAY,
|
424
|
-
ON_OPEN_FOCUS_DELAY,
|
425
|
-
showOverlay,
|
426
|
-
hideOverlay,
|
427
|
-
lockScroll,
|
428
|
-
unlockScroll,
|
429
|
-
openWithOverlay,
|
430
|
-
closeWithOverlay,
|
431
|
-
initFloatingUi,
|
432
|
-
focusTrigger,
|
433
|
-
getFocusableElements,
|
434
|
-
getSameLevelItems,
|
435
|
-
showContent,
|
436
|
-
hideContent,
|
437
|
-
}
|