@sesionario/blocks 1.20.0 → 1.21.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.
- package/README.md +75 -0
- package/dist/index.cjs +348 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +166 -2
- package/dist/index.d.ts +166 -2
- package/dist/index.js +344 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,81 @@ This package is the Sesionario-specific successor to `@algenium/blocks`. It ship
|
|
|
6
6
|
|
|
7
7
|
Shared feedback patterns include `ConfirmDestructiveDialog` (confirm before delete/mute and similar irreversible actions).
|
|
8
8
|
|
|
9
|
+
### Read-first editable sections (`EditableSection`, `DataList`, `FieldMessage`)
|
|
10
|
+
|
|
11
|
+
Settings and profile data should be readable by default, then turn into a real `<form>` when the person chooses Edit. The primitives are chrome-free — no Card, border, or title — so you place actions in your own layout (`CardAction`, page header, dialog, or a bare section).
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import {
|
|
15
|
+
EditableSection,
|
|
16
|
+
DataList,
|
|
17
|
+
DataListItem,
|
|
18
|
+
FieldMessage,
|
|
19
|
+
} from "@sesionario/blocks";
|
|
20
|
+
|
|
21
|
+
<EditableSection
|
|
22
|
+
labelledBy="fiscal-title"
|
|
23
|
+
isDirty={dirty}
|
|
24
|
+
onDiscard={() => reset()}
|
|
25
|
+
onSave={async () => {
|
|
26
|
+
/* throw on validation/API failure so edit mode stays open */
|
|
27
|
+
await save();
|
|
28
|
+
}}
|
|
29
|
+
labels={{
|
|
30
|
+
edit: t("edit"),
|
|
31
|
+
save: t("save"),
|
|
32
|
+
saving: t("saving"),
|
|
33
|
+
cancel: t("cancel"),
|
|
34
|
+
saved: t("saved"),
|
|
35
|
+
}}
|
|
36
|
+
readView={() => (
|
|
37
|
+
<DataList>
|
|
38
|
+
<DataListItem label="RFC">{rfc}</DataListItem>
|
|
39
|
+
</DataList>
|
|
40
|
+
)}
|
|
41
|
+
editView={() => (
|
|
42
|
+
<div className="flex flex-col gap-1.5">
|
|
43
|
+
<label htmlFor="rfc">RFC</label>
|
|
44
|
+
<input id="rfc" value={rfc} onChange={...} aria-invalid={!!error} aria-describedby="rfc-err" />
|
|
45
|
+
<FieldMessage id="rfc-err">{error}</FieldMessage>
|
|
46
|
+
</div>
|
|
47
|
+
)}
|
|
48
|
+
>
|
|
49
|
+
{({ actions, content, status }) => (
|
|
50
|
+
<Card>
|
|
51
|
+
<CardHeader>
|
|
52
|
+
<CardTitle id="fiscal-title">Datos fiscales</CardTitle>
|
|
53
|
+
<CardAction>{actions}</CardAction>
|
|
54
|
+
</CardHeader>
|
|
55
|
+
<CardContent>
|
|
56
|
+
{content}
|
|
57
|
+
{status}
|
|
58
|
+
</CardContent>
|
|
59
|
+
</Card>
|
|
60
|
+
)}
|
|
61
|
+
</EditableSection>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Headless alternative: `useEditableSection` for card-less surfaces (dialogs, table rows, page headers).
|
|
65
|
+
|
|
66
|
+
Optional progressive-enhancement CSS for a smoother height change (Chromium 129+; no-op elsewhere). Honor reduced motion:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
@supports (interpolate-size: allow-keywords) {
|
|
70
|
+
.sesionario-editable-section-content {
|
|
71
|
+
interpolate-size: allow-keywords;
|
|
72
|
+
transition: min-height 200ms ease;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
@media (prefers-reduced-motion: reduce) {
|
|
76
|
+
.sesionario-editable-section-content {
|
|
77
|
+
transition: none;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Pass `stableHeight` for small (1–2 field) sections if you want later toggles to keep a cached `min-height`.
|
|
83
|
+
|
|
9
84
|
## Install
|
|
10
85
|
|
|
11
86
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -456,6 +456,348 @@ function ConfirmDestructiveDialog({
|
|
|
456
456
|
] })
|
|
457
457
|
] }) });
|
|
458
458
|
}
|
|
459
|
+
|
|
460
|
+
// src/components/editable/types.ts
|
|
461
|
+
var DEFAULT_EDITABLE_SECTION_LABELS = {
|
|
462
|
+
edit: "Editar",
|
|
463
|
+
save: "Guardar",
|
|
464
|
+
saving: "Guardando\u2026",
|
|
465
|
+
cancel: "Cancelar",
|
|
466
|
+
saved: "Guardado",
|
|
467
|
+
discardTitle: "\xBFDescartar cambios?",
|
|
468
|
+
discardDescription: "Si sales ahora, se perder\xE1n los cambios que no hayas guardado.",
|
|
469
|
+
discardConfirm: "Descartar",
|
|
470
|
+
discardCancel: "Seguir editando"
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// src/components/editable/useEditableSection.ts
|
|
474
|
+
function focusFirstField(container) {
|
|
475
|
+
if (!container) return;
|
|
476
|
+
const target = container.querySelector(
|
|
477
|
+
"[data-autofocus], input:not([type='hidden']):not([disabled]), select:not([disabled]), textarea:not([disabled]), [contenteditable='true']"
|
|
478
|
+
);
|
|
479
|
+
target?.focus();
|
|
480
|
+
}
|
|
481
|
+
function useEditableSection({
|
|
482
|
+
onSave,
|
|
483
|
+
onDiscard,
|
|
484
|
+
isDirty = false,
|
|
485
|
+
labelledBy,
|
|
486
|
+
title,
|
|
487
|
+
labels,
|
|
488
|
+
stableHeight = false
|
|
489
|
+
}) {
|
|
490
|
+
const resolvedLabels = {
|
|
491
|
+
...DEFAULT_EDITABLE_SECTION_LABELS,
|
|
492
|
+
...labels
|
|
493
|
+
};
|
|
494
|
+
const [mode, setMode] = React7.useState("reading");
|
|
495
|
+
const [status, setStatus] = React7.useState(null);
|
|
496
|
+
const [confirmOpen, setConfirmOpen] = React7.useState(false);
|
|
497
|
+
const [minHeightPx, setMinHeightPx] = React7.useState(void 0);
|
|
498
|
+
const contentRef = React7.useRef(null);
|
|
499
|
+
const editButtonRef = React7.useRef(null);
|
|
500
|
+
const measuredHeightRef = React7.useRef(0);
|
|
501
|
+
const shouldFocusEditRef = React7.useRef(false);
|
|
502
|
+
const shouldFocusFirstFieldRef = React7.useRef(false);
|
|
503
|
+
const editButtonId = React7.useId();
|
|
504
|
+
const contentFormId = React7.useId();
|
|
505
|
+
const isEditing = mode === "editing" || mode === "saving";
|
|
506
|
+
const isSaving = mode === "saving";
|
|
507
|
+
React7.useEffect(() => {
|
|
508
|
+
if (mode === "reading" && shouldFocusEditRef.current) {
|
|
509
|
+
shouldFocusEditRef.current = false;
|
|
510
|
+
editButtonRef.current?.focus();
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
if (mode === "editing" && shouldFocusFirstFieldRef.current) {
|
|
514
|
+
shouldFocusFirstFieldRef.current = false;
|
|
515
|
+
const invalid = contentRef.current?.querySelector(
|
|
516
|
+
"[aria-invalid='true']"
|
|
517
|
+
);
|
|
518
|
+
if (invalid) {
|
|
519
|
+
invalid.focus();
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
focusFirstField(contentRef.current);
|
|
523
|
+
}
|
|
524
|
+
}, [mode]);
|
|
525
|
+
const exitToReading = React7.useCallback(() => {
|
|
526
|
+
setConfirmOpen(false);
|
|
527
|
+
shouldFocusEditRef.current = true;
|
|
528
|
+
setMode("reading");
|
|
529
|
+
onDiscard?.();
|
|
530
|
+
}, [onDiscard]);
|
|
531
|
+
const startEdit = React7.useCallback(() => {
|
|
532
|
+
setStatus(null);
|
|
533
|
+
shouldFocusFirstFieldRef.current = true;
|
|
534
|
+
setMode("editing");
|
|
535
|
+
}, []);
|
|
536
|
+
const requestCancel = React7.useCallback(() => {
|
|
537
|
+
if (isSaving) return;
|
|
538
|
+
if (isDirty) {
|
|
539
|
+
setConfirmOpen(true);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
exitToReading();
|
|
543
|
+
}, [exitToReading, isDirty, isSaving]);
|
|
544
|
+
const handleSubmit = React7.useCallback(
|
|
545
|
+
(event) => {
|
|
546
|
+
event.preventDefault();
|
|
547
|
+
if (isSaving) return;
|
|
548
|
+
void (async () => {
|
|
549
|
+
setMode("saving");
|
|
550
|
+
setStatus(null);
|
|
551
|
+
try {
|
|
552
|
+
await onSave();
|
|
553
|
+
setStatus(resolvedLabels.saved);
|
|
554
|
+
shouldFocusEditRef.current = true;
|
|
555
|
+
setMode("reading");
|
|
556
|
+
} catch {
|
|
557
|
+
shouldFocusFirstFieldRef.current = true;
|
|
558
|
+
setMode("editing");
|
|
559
|
+
}
|
|
560
|
+
})();
|
|
561
|
+
},
|
|
562
|
+
[isSaving, onSave, resolvedLabels.saved]
|
|
563
|
+
);
|
|
564
|
+
const handleFormKeyDown = React7.useCallback(
|
|
565
|
+
(event) => {
|
|
566
|
+
if (event.key !== "Escape") return;
|
|
567
|
+
event.preventDefault();
|
|
568
|
+
requestCancel();
|
|
569
|
+
},
|
|
570
|
+
[requestCancel]
|
|
571
|
+
);
|
|
572
|
+
React7.useEffect(() => {
|
|
573
|
+
if (!stableHeight || !isEditing) return;
|
|
574
|
+
const el = contentRef.current;
|
|
575
|
+
if (!el) return;
|
|
576
|
+
const measure = () => {
|
|
577
|
+
const height = el.getBoundingClientRect().height;
|
|
578
|
+
if (height > measuredHeightRef.current) {
|
|
579
|
+
measuredHeightRef.current = height;
|
|
580
|
+
setMinHeightPx(height);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
measure();
|
|
584
|
+
const observer = new ResizeObserver(measure);
|
|
585
|
+
observer.observe(el);
|
|
586
|
+
return () => observer.disconnect();
|
|
587
|
+
}, [isEditing, stableHeight]);
|
|
588
|
+
const editButtonNameProps = labelledBy != null ? { "aria-labelledby": `${labelledBy} ${editButtonId}` } : title != null && title.length > 0 ? { "aria-label": `${resolvedLabels.edit} ${title}` } : { "aria-label": resolvedLabels.edit };
|
|
589
|
+
return {
|
|
590
|
+
mode,
|
|
591
|
+
isEditing,
|
|
592
|
+
isSaving,
|
|
593
|
+
startEdit,
|
|
594
|
+
requestCancel,
|
|
595
|
+
formProps: {
|
|
596
|
+
onSubmit: handleSubmit,
|
|
597
|
+
onKeyDown: handleFormKeyDown,
|
|
598
|
+
noValidate: true
|
|
599
|
+
},
|
|
600
|
+
contentRef,
|
|
601
|
+
editButtonRef,
|
|
602
|
+
contentFormId,
|
|
603
|
+
editButtonProps: {
|
|
604
|
+
type: "button",
|
|
605
|
+
id: editButtonId,
|
|
606
|
+
onClick: startEdit,
|
|
607
|
+
ref: editButtonRef,
|
|
608
|
+
...editButtonNameProps
|
|
609
|
+
},
|
|
610
|
+
saveButtonProps: {
|
|
611
|
+
type: "submit",
|
|
612
|
+
disabled: isSaving
|
|
613
|
+
},
|
|
614
|
+
cancelButtonProps: {
|
|
615
|
+
type: "button",
|
|
616
|
+
onClick: requestCancel,
|
|
617
|
+
disabled: isSaving
|
|
618
|
+
},
|
|
619
|
+
status,
|
|
620
|
+
statusProps: {
|
|
621
|
+
role: "status",
|
|
622
|
+
"aria-live": "polite",
|
|
623
|
+
className: "sr-only"
|
|
624
|
+
},
|
|
625
|
+
confirmDiscard: {
|
|
626
|
+
open: confirmOpen,
|
|
627
|
+
onOpenChange: setConfirmOpen,
|
|
628
|
+
title: resolvedLabels.discardTitle,
|
|
629
|
+
description: resolvedLabels.discardDescription,
|
|
630
|
+
confirmLabel: resolvedLabels.discardConfirm,
|
|
631
|
+
cancelLabel: resolvedLabels.discardCancel,
|
|
632
|
+
onConfirm: exitToReading
|
|
633
|
+
},
|
|
634
|
+
resolvedLabels,
|
|
635
|
+
contentStyle: stableHeight && minHeightPx != null ? { minHeight: minHeightPx } : void 0,
|
|
636
|
+
actionsClassName: "flex min-h-9 min-w-[11rem] flex-wrap items-center justify-end gap-2"
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
function EditableSection({
|
|
640
|
+
readView,
|
|
641
|
+
editView,
|
|
642
|
+
children,
|
|
643
|
+
className,
|
|
644
|
+
...options
|
|
645
|
+
}) {
|
|
646
|
+
const section = useEditableSection(options);
|
|
647
|
+
const {
|
|
648
|
+
isEditing,
|
|
649
|
+
isSaving,
|
|
650
|
+
formProps,
|
|
651
|
+
contentRef,
|
|
652
|
+
contentFormId,
|
|
653
|
+
editButtonProps,
|
|
654
|
+
saveButtonProps,
|
|
655
|
+
cancelButtonProps,
|
|
656
|
+
status,
|
|
657
|
+
statusProps,
|
|
658
|
+
confirmDiscard,
|
|
659
|
+
resolvedLabels,
|
|
660
|
+
contentStyle,
|
|
661
|
+
actionsClassName,
|
|
662
|
+
mode
|
|
663
|
+
} = section;
|
|
664
|
+
const actionButtons = !isEditing ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", size: "sm", ...editButtonProps, children: resolvedLabels.edit }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
665
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", size: "sm", ...cancelButtonProps, children: resolvedLabels.cancel }),
|
|
666
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
667
|
+
Button,
|
|
668
|
+
{
|
|
669
|
+
size: "sm",
|
|
670
|
+
type: "submit",
|
|
671
|
+
form: contentFormId,
|
|
672
|
+
disabled: saveButtonProps.disabled,
|
|
673
|
+
children: isSaving ? resolvedLabels.saving : resolvedLabels.save
|
|
674
|
+
}
|
|
675
|
+
)
|
|
676
|
+
] });
|
|
677
|
+
const actions = /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "editable-section-actions", className: actionsClassName, children: actionButtons });
|
|
678
|
+
const content = isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
679
|
+
"form",
|
|
680
|
+
{
|
|
681
|
+
id: contentFormId,
|
|
682
|
+
ref: contentRef,
|
|
683
|
+
"data-slot": "editable-section-content",
|
|
684
|
+
className: cn("sesionario-editable-section-content space-y-4"),
|
|
685
|
+
style: contentStyle,
|
|
686
|
+
...formProps,
|
|
687
|
+
children: editView()
|
|
688
|
+
}
|
|
689
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
690
|
+
"div",
|
|
691
|
+
{
|
|
692
|
+
ref: contentRef,
|
|
693
|
+
"data-slot": "editable-section-content",
|
|
694
|
+
className: "sesionario-editable-section-content",
|
|
695
|
+
style: contentStyle,
|
|
696
|
+
children: readView()
|
|
697
|
+
}
|
|
698
|
+
);
|
|
699
|
+
const statusNode = /* @__PURE__ */ jsxRuntime.jsx("span", { ...statusProps, "data-slot": "editable-section-status", children: status });
|
|
700
|
+
const dialog = /* @__PURE__ */ jsxRuntime.jsx(
|
|
701
|
+
ConfirmDestructiveDialog,
|
|
702
|
+
{
|
|
703
|
+
open: confirmDiscard.open,
|
|
704
|
+
onOpenChange: confirmDiscard.onOpenChange,
|
|
705
|
+
title: confirmDiscard.title,
|
|
706
|
+
description: confirmDiscard.description,
|
|
707
|
+
confirmLabel: confirmDiscard.confirmLabel,
|
|
708
|
+
cancelLabel: confirmDiscard.cancelLabel,
|
|
709
|
+
onConfirm: confirmDiscard.onConfirm
|
|
710
|
+
}
|
|
711
|
+
);
|
|
712
|
+
if (children) {
|
|
713
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
714
|
+
children({
|
|
715
|
+
actions,
|
|
716
|
+
content,
|
|
717
|
+
status: statusNode,
|
|
718
|
+
mode,
|
|
719
|
+
isSaving,
|
|
720
|
+
isEditing
|
|
721
|
+
}),
|
|
722
|
+
dialog
|
|
723
|
+
] });
|
|
724
|
+
}
|
|
725
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "editable-section", className: cn("space-y-4", className), children: [
|
|
726
|
+
actions,
|
|
727
|
+
content,
|
|
728
|
+
statusNode,
|
|
729
|
+
dialog
|
|
730
|
+
] });
|
|
731
|
+
}
|
|
732
|
+
function DataList({ className, ...props }) {
|
|
733
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
734
|
+
"dl",
|
|
735
|
+
{
|
|
736
|
+
"data-slot": "data-list",
|
|
737
|
+
className: cn("grid gap-4 sm:grid-cols-2", className),
|
|
738
|
+
...props
|
|
739
|
+
}
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
function DataListItem({
|
|
743
|
+
label,
|
|
744
|
+
children,
|
|
745
|
+
empty = "\u2014",
|
|
746
|
+
className,
|
|
747
|
+
labelClassName,
|
|
748
|
+
valueClassName
|
|
749
|
+
}) {
|
|
750
|
+
const isEmpty = children == null || children === false || typeof children === "string" && children.trim().length === 0;
|
|
751
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
752
|
+
"div",
|
|
753
|
+
{
|
|
754
|
+
"data-slot": "data-list-item",
|
|
755
|
+
className: cn("flex flex-col gap-1.5", className),
|
|
756
|
+
children: [
|
|
757
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
758
|
+
"dt",
|
|
759
|
+
{
|
|
760
|
+
className: cn(
|
|
761
|
+
"text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
762
|
+
labelClassName
|
|
763
|
+
),
|
|
764
|
+
children: label
|
|
765
|
+
}
|
|
766
|
+
),
|
|
767
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
768
|
+
"dd",
|
|
769
|
+
{
|
|
770
|
+
className: cn(
|
|
771
|
+
"text-sm wrap-break-word",
|
|
772
|
+
isEmpty && "text-muted-foreground",
|
|
773
|
+
valueClassName
|
|
774
|
+
),
|
|
775
|
+
children: isEmpty ? empty : children
|
|
776
|
+
}
|
|
777
|
+
)
|
|
778
|
+
]
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
function FieldMessage({
|
|
783
|
+
id,
|
|
784
|
+
children,
|
|
785
|
+
className,
|
|
786
|
+
...props
|
|
787
|
+
}) {
|
|
788
|
+
const hasMessage = children != null && children !== false && !(typeof children === "string" && children.trim().length === 0);
|
|
789
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
790
|
+
"p",
|
|
791
|
+
{
|
|
792
|
+
id,
|
|
793
|
+
role: hasMessage ? "alert" : void 0,
|
|
794
|
+
"data-slot": "field-message",
|
|
795
|
+
className: cn("min-h-5 text-xs text-destructive", className),
|
|
796
|
+
...props,
|
|
797
|
+
children: hasMessage ? children : "\xA0"
|
|
798
|
+
}
|
|
799
|
+
);
|
|
800
|
+
}
|
|
459
801
|
var COLLAPSED_MAX_HEIGHT_REM = 11;
|
|
460
802
|
function ExpandableText({
|
|
461
803
|
children,
|
|
@@ -8340,8 +8682,12 @@ exports.BubbleGroup = BubbleGroup;
|
|
|
8340
8682
|
exports.BubbleReactions = BubbleReactions;
|
|
8341
8683
|
exports.ChatMessageList = ChatMessageList;
|
|
8342
8684
|
exports.ConfirmDestructiveDialog = ConfirmDestructiveDialog;
|
|
8685
|
+
exports.DEFAULT_EDITABLE_SECTION_LABELS = DEFAULT_EDITABLE_SECTION_LABELS;
|
|
8686
|
+
exports.DataList = DataList;
|
|
8687
|
+
exports.DataListItem = DataListItem;
|
|
8343
8688
|
exports.DropdownMenuItem = DropdownMenuItem;
|
|
8344
8689
|
exports.DropdownMenuSeparator = DropdownMenuSeparator;
|
|
8690
|
+
exports.EditableSection = EditableSection;
|
|
8345
8691
|
exports.EmojiInput = EmojiInput;
|
|
8346
8692
|
exports.EmojiPicker = EmojiPicker;
|
|
8347
8693
|
exports.EmojiPickerPopover = EmojiPickerPopover;
|
|
@@ -8356,6 +8702,7 @@ exports.EmptyTitle = EmptyTitle;
|
|
|
8356
8702
|
exports.ErrorState = ErrorState;
|
|
8357
8703
|
exports.ExpandableText = ExpandableText;
|
|
8358
8704
|
exports.FeedVideoPlayer = FeedVideoPlayer;
|
|
8705
|
+
exports.FieldMessage = FieldMessage;
|
|
8359
8706
|
exports.ImageLightbox = ImageLightbox;
|
|
8360
8707
|
exports.LanguageContext = LanguageContext;
|
|
8361
8708
|
exports.LanguageSwitcher = LanguageSwitcher;
|
|
@@ -8414,6 +8761,7 @@ exports.paymentTypeFromStripeBrand = paymentTypeFromStripeBrand;
|
|
|
8414
8761
|
exports.shouldRetryLiveEdge404 = shouldRetryLiveEdge404;
|
|
8415
8762
|
exports.useDebouncedValue = useDebouncedValue;
|
|
8416
8763
|
exports.useDebouncedValueStrict = useDebouncedValueStrict;
|
|
8764
|
+
exports.useEditableSection = useEditableSection;
|
|
8417
8765
|
exports.useFeedExclusivePlayback = useFeedExclusivePlayback;
|
|
8418
8766
|
exports.useHlsPlayback = useHlsPlayback;
|
|
8419
8767
|
exports.useLanguageContext = useLanguageContext;
|