@ryuzaki13/react-foundation-ui 0.1.0 → 1.0.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/dist/badge/Badge.d.ts.map +1 -1
- package/dist/badge/index.js +1 -1
- package/dist/badge/stories/Badge.stories.js +1 -1
- package/dist/base-table/index.js +1 -1
- package/dist/base-table/lib/columnPinning.d.ts.map +1 -1
- package/dist/base-table/model/useTableColumnOrder.d.ts +1 -1
- package/dist/base-table/model/useTableColumnOrder.d.ts.map +1 -1
- package/dist/base-table/model/useTableColumnSizing.d.ts +1 -1
- package/dist/base-table/model/useTableColumnSizing.d.ts.map +1 -1
- package/dist/base-table/ui/BaseTable.d.ts +2 -2
- package/dist/base-table/ui/BaseTable.d.ts.map +1 -1
- package/dist/base-table/ui/BaseTableHeaderCell.d.ts.map +1 -1
- package/dist/base-table/ui/FormattedTableCell.d.ts.map +1 -1
- package/dist/check-box/CheckBox.d.ts.map +1 -1
- package/dist/check-box/index.js +1 -1
- package/dist/check-box/stories/CheckBox.stories.js +1 -1
- package/dist/chunks/{BadgeList-DHW_Ktr3.js → BadgeList-6qL9oNAp.js} +5 -5
- package/dist/chunks/BadgeList-6qL9oNAp.js.map +1 -0
- package/dist/chunks/{CalendarView-B75faWIU.js → CalendarView-DjShdvRD.js} +42 -42
- package/dist/chunks/{CalendarView-B75faWIU.js.map → CalendarView-DjShdvRD.js.map} +1 -1
- package/dist/chunks/{CheckBox-Cck5w1Ud.js → CheckBox-CulnjNvJ.js} +9 -9
- package/dist/chunks/CheckBox-CulnjNvJ.js.map +1 -0
- package/dist/chunks/{DateInput-CINDYueM.js → DateInput-LSSvObtg.js} +3 -3
- package/dist/chunks/DateInput-LSSvObtg.js.map +1 -0
- package/dist/chunks/Dialog-BPS4BeWZ.js.map +1 -1
- package/dist/chunks/{DisclosureGroup-0BtaXO54.js → DisclosureGroup-Plk2M_Vl.js} +9 -9
- package/dist/chunks/DisclosureGroup-Plk2M_Vl.js.map +1 -0
- package/dist/chunks/{DropZone-hf7Em__0.js → DropZone-DPGTpHI6.js} +7 -7
- package/dist/chunks/DropZone-DPGTpHI6.js.map +1 -0
- package/dist/chunks/DropdownMenu-Ds-trH4M.js.map +1 -1
- package/dist/chunks/Flex-DbBdq336.js.map +1 -1
- package/dist/chunks/Grid-ByIIytjh.js.map +1 -1
- package/dist/chunks/{Input-Ce2HXBUc.js → Input-Wrew1puH.js} +30 -30
- package/dist/chunks/Input-Wrew1puH.js.map +1 -0
- package/dist/chunks/{InputDateTime-DPtY_4Od.js → InputDateTime-2PCX8an8.js} +2 -2
- package/dist/chunks/{InputDateTime-DPtY_4Od.js.map → InputDateTime-2PCX8an8.js.map} +1 -1
- package/dist/chunks/{InputFile-ga5yJmdZ.js → InputFile-Ca-bRo93.js} +2 -2
- package/dist/chunks/InputFile-Ca-bRo93.js.map +1 -0
- package/dist/chunks/{InputFiles-Or2Nvfgk.js → InputFiles-pI9rQXOI.js} +22 -22
- package/dist/chunks/InputFiles-pI9rQXOI.js.map +1 -0
- package/dist/chunks/{InputImage-BeA5WJz1.js → InputImage-B522AQzl.js} +2 -2
- package/dist/chunks/{InputImage-BeA5WJz1.js.map → InputImage-B522AQzl.js.map} +1 -1
- package/dist/chunks/{LabeledExpandableActionPanel-Bx-DWmYz.js → LabeledExpandableActionPanel-CWmOSWeS.js} +12 -12
- package/dist/chunks/LabeledExpandableActionPanel-CWmOSWeS.js.map +1 -0
- package/dist/chunks/{Listbox-CY1wQOCP.js → Listbox-B6F_IKQv.js} +22 -22
- package/dist/chunks/Listbox-B6F_IKQv.js.map +1 -0
- package/dist/chunks/{MultiSelect-CBqTylqO.js → MultiSelect-CUXA8gx-.js} +12 -12
- package/dist/chunks/{MultiSelect-CBqTylqO.js.map → MultiSelect-CUXA8gx-.js.map} +1 -1
- package/dist/chunks/{NotificationsHost-BQc-zOr2.js → NotificationsHost-Bnq7xFKO.js} +24 -24
- package/dist/chunks/NotificationsHost-Bnq7xFKO.js.map +1 -0
- package/dist/chunks/{PresetRangeDateInput-YBQm_4Fb.js → PresetRangeDateInput-B_8jsilZ.js} +2 -2
- package/dist/chunks/{PresetRangeDateInput-YBQm_4Fb.js.map → PresetRangeDateInput-B_8jsilZ.js.map} +1 -1
- package/dist/chunks/{RadioButton-DJp31HFR.js → RadioButton-D5vPW4Yr.js} +8 -8
- package/dist/chunks/RadioButton-D5vPW4Yr.js.map +1 -0
- package/dist/chunks/{Select-B7k_8_Lf.js → Select-CoAYWNOn.js} +10 -10
- package/dist/chunks/Select-CoAYWNOn.js.map +1 -0
- package/dist/chunks/{SerializableSelect-53uNCqdE.js → SerializableSelect-awBOWKTj.js} +2 -2
- package/dist/chunks/{SerializableSelect-53uNCqdE.js.map → SerializableSelect-awBOWKTj.js.map} +1 -1
- package/dist/chunks/{SingleDateTimeInput-CwvIbwje.js → SingleDateTimeInput-o44Vlwdk.js} +19 -19
- package/dist/chunks/SingleDateTimeInput-o44Vlwdk.js.map +1 -0
- package/dist/chunks/{StateSelect-D0wuUdT9.js → StateSelect-abZq176J.js} +2 -2
- package/dist/chunks/{StateSelect-D0wuUdT9.js.map → StateSelect-abZq176J.js.map} +1 -1
- package/dist/chunks/{Switch-B476FBUD.js → Switch-DHMnZVmN.js} +9 -9
- package/dist/chunks/Switch-DHMnZVmN.js.map +1 -0
- package/dist/chunks/{TextEditorLexicalClient-DcixYuo4.js → TextEditorLexicalClient-Dt4eaPA3.js} +4 -4
- package/dist/chunks/{TextEditorLexicalClient-DcixYuo4.js.map → TextEditorLexicalClient-Dt4eaPA3.js.map} +1 -1
- package/dist/chunks/{Textarea-DeJJjjkI.js → Textarea-DOVrPH4I.js} +2 -2
- package/dist/chunks/{Textarea-DeJJjjkI.js.map → Textarea-DOVrPH4I.js.map} +1 -1
- package/dist/chunks/TimePanel-_kF2RtHk.js.map +1 -1
- package/dist/chunks/{TreeMultiSelect-DRYNx7u5.js → TreeMultiSelect-C76RYavo.js} +2 -2
- package/dist/chunks/{TreeMultiSelect-DRYNx7u5.js.map → TreeMultiSelect-C76RYavo.js.map} +1 -1
- package/dist/chunks/{TreePickerBase-DYzTsSBQ.js → TreePickerBase-qNHIWbYL.js} +155 -155
- package/dist/chunks/TreePickerBase-qNHIWbYL.js.map +1 -0
- package/dist/chunks/{TreeSelect-DGLDu6qc.js → TreeSelect-LEhNdPCX.js} +2 -2
- package/dist/chunks/{TreeSelect-DGLDu6qc.js.map → TreeSelect-LEhNdPCX.js.map} +1 -1
- package/dist/chunks/{base-table-DVje02Zi.js → base-table-ij2guVMB.js} +3 -3
- package/dist/chunks/base-table-ij2guVMB.js.map +1 -0
- package/dist/chunks/{layout-picker-BA9vA8JI.js → layout-picker-CzZ8Xzkk.js} +9 -9
- package/dist/chunks/layout-picker-CzZ8Xzkk.js.map +1 -0
- package/dist/chunks/{misc-DrmMj8GO.js → misc-Bj0y3ERC.js} +54 -54
- package/dist/chunks/misc-Bj0y3ERC.js.map +1 -0
- package/dist/chunks/{modal-DqVcZws_.js → modal-B4ivQb2h.js} +10 -10
- package/dist/chunks/modal-B4ivQb2h.js.map +1 -0
- package/dist/chunks/{picker-Cj4RnJh6.js → picker-gIUs0nE_.js} +13 -13
- package/dist/chunks/picker-gIUs0nE_.js.map +1 -0
- package/dist/chunks/popover-C79P5bm2.js.map +1 -1
- package/dist/chunks/{slider-34wxzKkG.js → slider-CigVo4Ju.js} +3 -3
- package/dist/chunks/slider-CigVo4Ju.js.map +1 -0
- package/dist/chunks/{sortable-CwDHC3CA.js → sortable-BZqnZ_LA.js} +10 -10
- package/dist/chunks/sortable-BZqnZ_LA.js.map +1 -0
- package/dist/chunks/{table-BYA0hCj7.js → table-CK-CM2zD.js} +2 -2
- package/dist/chunks/table-CK-CM2zD.js.map +1 -0
- package/dist/chunks/table-column-interactions-DPyJDD7P.js.map +1 -1
- package/dist/chunks/{tabs-CjU2KCgs.js → tabs-D5ikIIng.js} +2 -2
- package/dist/chunks/{tabs-CjU2KCgs.js.map → tabs-D5ikIIng.js.map} +1 -1
- package/dist/chunks/ui.module-BisoTevy.js.map +1 -1
- package/dist/context-menu/components/MenuContent.d.ts.map +1 -1
- package/dist/context-menu/components/MenuContext.d.ts.map +1 -1
- package/dist/context-menu/components/MenuRoot.d.ts.map +1 -1
- package/dist/context-menu/components/RadialMenuContent.d.ts.map +1 -1
- package/dist/date-input/index.js +2 -2
- package/dist/date-input/lib/types.d.ts.map +1 -1
- package/dist/date-input/stories/DateInput.stories.js +2 -2
- package/dist/date-input/ui/CalendarView.d.ts.map +1 -1
- package/dist/date-input/ui/DateInput.d.ts.map +1 -1
- package/dist/date-range-preset-select/stories/DateRangePresetSelect.stories.js +1 -1
- package/dist/date-time-input/index.js +1 -1
- package/dist/date-time-input/lib/dateTimeValue.d.ts.map +1 -1
- package/dist/date-time-input/stories/SingleDateTimeInput.stories.js +1 -1
- package/dist/date-time-input/ui/SingleDateTimeInput.d.ts.map +1 -1
- package/dist/dialog/Dialog.d.ts.map +1 -1
- package/dist/disclosure/Disclosure.d.ts.map +1 -1
- package/dist/disclosure/index.js +1 -1
- package/dist/disclosure/stories/Disclosure.stories.js +1 -1
- package/dist/drop-zone/DropZone.d.ts.map +1 -1
- package/dist/drop-zone/index.js +1 -1
- package/dist/drop-zone/stories/DropZone.stories.d.ts.map +1 -1
- package/dist/drop-zone/stories/DropZone.stories.js +1 -1
- package/dist/drop-zone/stories/DropZone.stories.js.map +1 -1
- package/dist/errors/ErrorDisplay.d.ts.map +1 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/expandable-action-panel/ExpandableActionPanel.d.ts.map +1 -1
- package/dist/expandable-action-panel/index.js +1 -1
- package/dist/expandable-action-panel/stories/ExpandableActionPanel.stories.js +4 -4
- package/dist/image/index.js +3 -3
- package/dist/image/index.js.map +1 -1
- package/dist/image/ui/ImageSelection.d.ts.map +1 -1
- package/dist/input/Input.d.ts.map +1 -1
- package/dist/input/index.js +1 -1
- package/dist/input/stories/Input.stories.js +1 -1
- package/dist/input-date-time/index.js +1 -1
- package/dist/input-date-time/stories/InputDateTime.stories.js +1 -1
- package/dist/input-file/InputFile.d.ts.map +1 -1
- package/dist/input-file/index.js +1 -1
- package/dist/input-file/stories/InputFile.stories.d.ts.map +1 -1
- package/dist/input-file/stories/InputFile.stories.js +1 -1
- package/dist/input-file/stories/InputFile.stories.js.map +1 -1
- package/dist/input-files/InputFilesList.d.ts.map +1 -1
- package/dist/input-files/index.js +1 -1
- package/dist/input-files/stories/InputFiles.stories.d.ts +1 -1
- package/dist/input-files/stories/InputFiles.stories.d.ts.map +1 -1
- package/dist/input-files/stories/InputFiles.stories.js +1 -1
- package/dist/input-files/stories/InputFiles.stories.js.map +1 -1
- package/dist/input-image/index.js +1 -1
- package/dist/input-image/stories/InputImage.stories.d.ts.map +1 -1
- package/dist/input-image/stories/InputImage.stories.js +1 -1
- package/dist/input-image/stories/InputImage.stories.js.map +1 -1
- package/dist/input-search/index.js +1 -1
- package/dist/layout-picker/index.js +1 -1
- package/dist/layout-picker/stories/LayoutPicker.stories.js +1 -1
- package/dist/layout-picker/ui/LayoutPicker.d.ts.map +1 -1
- package/dist/list/List.d.ts.map +1 -1
- package/dist/list/index.js +5 -5
- package/dist/list/index.js.map +1 -1
- package/dist/listbox/Listbox.d.ts.map +1 -1
- package/dist/listbox/index.js +1 -1
- package/dist/listbox/stories/Listbox.stories.js +1 -1
- package/dist/misc/CopyTextWrapper.d.ts.map +1 -1
- package/dist/misc/OneStepScroller.d.ts.map +1 -1
- package/dist/misc/StateIcon.d.ts.map +1 -1
- package/dist/misc/index.js +1 -1
- package/dist/modal/Modal.d.ts +5 -1
- package/dist/modal/Modal.d.ts.map +1 -1
- package/dist/modal/index.js +1 -1
- package/dist/modal/stories/Modal.stories.js +2 -2
- package/dist/multi-select/index.js +1130 -24
- package/dist/multi-select/index.js.map +1 -1
- package/dist/multi-select/model/useODataMultiSelect.d.ts +23 -0
- package/dist/multi-select/model/useODataMultiSelect.d.ts.map +1 -0
- package/dist/multi-select/ui/MultiSelect.d.ts +1 -1
- package/dist/multi-select/ui/MultiSelect.d.ts.map +1 -1
- package/dist/multi-select/ui/ODataDependentMultiSelect.d.ts +20 -0
- package/dist/multi-select/ui/ODataDependentMultiSelect.d.ts.map +1 -0
- package/dist/multi-select/ui/ODataDependentSegmentMultiSelect.d.ts +21 -0
- package/dist/multi-select/ui/ODataDependentSegmentMultiSelect.d.ts.map +1 -0
- package/dist/multi-select/ui/ODataMultiSelect.d.ts +7 -0
- package/dist/multi-select/ui/ODataMultiSelect.d.ts.map +1 -0
- package/dist/multi-select/ui/SerializableMultiSelect.d.ts.map +1 -1
- package/dist/multi-select/ui/index.d.ts +3 -0
- package/dist/multi-select/ui/index.d.ts.map +1 -1
- package/dist/multi-select/ui/stories/MultiSelect.stories.js +1 -1
- package/dist/multi-select/ui/stories/ODataMultiSelect.stories.d.ts +44 -0
- package/dist/multi-select/ui/stories/ODataMultiSelect.stories.d.ts.map +1 -0
- package/dist/notifications/index.js +1 -1
- package/dist/notifications/model/NotificationsProvider.d.ts.map +1 -1
- package/dist/notifications/ui/NotificationsHost.d.ts.map +1 -1
- package/dist/notifications/ui/stories/NotificationsHost.stories.js +1 -1
- package/dist/period-select/PeriodSelect.d.ts +1 -1
- package/dist/period-select/PeriodSelect.d.ts.map +1 -1
- package/dist/period-select/index.js.map +1 -1
- package/dist/period-select/lib/periodSelect.d.ts.map +1 -1
- package/dist/period-select/stories/PeriodSelect.stories.d.ts.map +1 -1
- package/dist/period-select/stories/PeriodSelect.stories.js +1 -1
- package/dist/period-select/stories/PeriodSelect.stories.js.map +1 -1
- package/dist/picker/PickerPopup.d.ts.map +1 -1
- package/dist/picker/PickerTriggerActions.d.ts.map +1 -1
- package/dist/picker/index.js +1 -1
- package/dist/picker/model/usePickerFloatingListbox.d.ts.map +1 -1
- package/dist/popover/FloatingPopover.d.ts.map +1 -1
- package/dist/popover/components/PopoverContent.d.ts.map +1 -1
- package/dist/popover/components/PopoverContext.d.ts.map +1 -1
- package/dist/popover/stories/Popover.stories.js +1 -1
- package/dist/preset-range-date-input/index.js +1 -1
- package/dist/preset-range-date-input/ui/stories/PresetRangeDateInput.stories.js +1 -1
- package/dist/preset-select/index.js +1 -1
- package/dist/radio-button/RadioButton.d.ts.map +1 -1
- package/dist/radio-button/index.js +1 -1
- package/dist/radio-button/stories/RadioButton.stories.js +1 -1
- package/dist/select/ODataSelect.d.ts +9 -0
- package/dist/select/ODataSelect.d.ts.map +1 -0
- package/dist/select/Select.d.ts.map +1 -1
- package/dist/select/index.js +2 -2
- package/dist/select/model/useODataSelect.d.ts +25 -0
- package/dist/select/model/useODataSelect.d.ts.map +1 -0
- package/dist/select/model/useODataSelectBase.d.ts +24 -0
- package/dist/select/model/useODataSelectBase.d.ts.map +1 -0
- package/dist/select/stories/ODataSelect.stories.d.ts +46 -0
- package/dist/select/stories/ODataSelect.stories.d.ts.map +1 -0
- package/dist/select/stories/Select.stories.js +1 -1
- package/dist/select/stories/SerializableSelect.stories.js +1 -1
- package/dist/select/stories/odataStoryCollection.d.ts +2 -0
- package/dist/select/stories/odataStoryCollection.d.ts.map +1 -0
- package/dist/select/stories/odataStoryFixtures.d.ts +35 -0
- package/dist/select/stories/odataStoryFixtures.d.ts.map +1 -0
- package/dist/simple-table/index.js +1 -1
- package/dist/simple-table/index.js.map +1 -1
- package/dist/slider/Slider.d.ts.map +1 -1
- package/dist/slider/index.js +1 -1
- package/dist/slider/stories/Slider.stories.js +1 -1
- package/dist/slider/stories/SliderInput.stories.js +1 -1
- package/dist/sortable/Sortable.d.ts.map +1 -1
- package/dist/sortable/SortableDragHandle.d.ts.map +1 -1
- package/dist/sortable/index.js +1 -1
- package/dist/sortable/stories/Sortable.stories.js +1 -1
- package/dist/state-select/index.js +1 -1
- package/dist/state-select/stories/StateSelect.stories.d.ts.map +1 -1
- package/dist/state-select/stories/StateSelect.stories.js +1 -1
- package/dist/state-select/stories/StateSelect.stories.js.map +1 -1
- package/dist/switch/Switch.d.ts.map +1 -1
- package/dist/switch/index.js +1 -1
- package/dist/switch/stories/Switch.stories.js +1 -1
- package/dist/table/Table.d.ts +1 -1
- package/dist/table/Table.d.ts.map +1 -1
- package/dist/table/index.js +1 -1
- package/dist/table/stories/Table.stories.d.ts +155 -0
- package/dist/table/stories/Table.stories.d.ts.map +1 -0
- package/dist/table-column-interactions/TableHeaderInteractionCell.d.ts.map +1 -1
- package/dist/tabs/index.js +1 -1
- package/dist/tabs/stories/Tabs.stories.d.ts.map +1 -1
- package/dist/tabs/stories/Tabs.stories.js +2 -2
- package/dist/tabs/stories/Tabs.stories.js.map +1 -1
- package/dist/text/TextOverflow.d.ts.map +1 -1
- package/dist/text/index.js.map +1 -1
- package/dist/text-editor/TextEditorLexicalClient.d.ts.map +1 -1
- package/dist/text-editor/index.js +2 -2
- package/dist/textarea/index.js +1 -1
- package/dist/textarea/stories/Textarea.stories.js +1 -1
- package/dist/tree-select/ODataTreeMultiSelect.d.ts +12 -0
- package/dist/tree-select/ODataTreeMultiSelect.d.ts.map +1 -0
- package/dist/tree-select/ODataTreeSelect.d.ts +13 -0
- package/dist/tree-select/ODataTreeSelect.d.ts.map +1 -0
- package/dist/tree-select/TreeNodeContent.d.ts.map +1 -1
- package/dist/tree-select/TreePickerBase.d.ts.map +1 -1
- package/dist/tree-select/index.js +2 -2
- package/dist/tree-select/model/buildODataTreeNodes.d.ts +12 -0
- package/dist/tree-select/model/buildODataTreeNodes.d.ts.map +1 -0
- package/dist/tree-select/model/resolveOrderedTreeSegmentItems.d.ts +4 -0
- package/dist/tree-select/model/resolveOrderedTreeSegmentItems.d.ts.map +1 -0
- package/dist/tree-select/model/useODataTreeData.d.ts +11 -0
- package/dist/tree-select/model/useODataTreeData.d.ts.map +1 -0
- package/dist/tree-select/stories/ODataTreeMultiSelect.stories.d.ts +55 -0
- package/dist/tree-select/stories/ODataTreeMultiSelect.stories.d.ts.map +1 -0
- package/dist/tree-select/stories/ODataTreeSelect.stories.d.ts +54 -0
- package/dist/tree-select/stories/ODataTreeSelect.stories.d.ts.map +1 -0
- package/dist/tree-select/stories/TreeMultiSelect.stories.js +1 -1
- package/dist/tree-select/stories/TreeSelect.stories.js +1 -1
- package/dist/tree-table/TreeTable.d.ts +1 -1
- package/dist/tree-table/TreeTable.d.ts.map +1 -1
- package/dist/tree-table/index.js +2 -2
- package/dist/tree-table/index.js.map +1 -1
- package/dist/tree-table/stories/TreeTable.stories.d.ts +158 -0
- package/dist/tree-table/stories/TreeTable.stories.d.ts.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -0
- package/package.json +15 -7
- package/dist/chunks/BadgeList-DHW_Ktr3.js.map +0 -1
- package/dist/chunks/CheckBox-Cck5w1Ud.js.map +0 -1
- package/dist/chunks/DateInput-CINDYueM.js.map +0 -1
- package/dist/chunks/DisclosureGroup-0BtaXO54.js.map +0 -1
- package/dist/chunks/DropZone-hf7Em__0.js.map +0 -1
- package/dist/chunks/Input-Ce2HXBUc.js.map +0 -1
- package/dist/chunks/InputFile-ga5yJmdZ.js.map +0 -1
- package/dist/chunks/InputFiles-Or2Nvfgk.js.map +0 -1
- package/dist/chunks/LabeledExpandableActionPanel-Bx-DWmYz.js.map +0 -1
- package/dist/chunks/Listbox-CY1wQOCP.js.map +0 -1
- package/dist/chunks/NotificationsHost-BQc-zOr2.js.map +0 -1
- package/dist/chunks/RadioButton-DJp31HFR.js.map +0 -1
- package/dist/chunks/Select-B7k_8_Lf.js.map +0 -1
- package/dist/chunks/SingleDateTimeInput-CwvIbwje.js.map +0 -1
- package/dist/chunks/Switch-B476FBUD.js.map +0 -1
- package/dist/chunks/TreePickerBase-DYzTsSBQ.js.map +0 -1
- package/dist/chunks/base-table-DVje02Zi.js.map +0 -1
- package/dist/chunks/layout-picker-BA9vA8JI.js.map +0 -1
- package/dist/chunks/misc-DrmMj8GO.js.map +0 -1
- package/dist/chunks/modal-DqVcZws_.js.map +0 -1
- package/dist/chunks/picker-Cj4RnJh6.js.map +0 -1
- package/dist/chunks/slider-34wxzKkG.js.map +0 -1
- package/dist/chunks/sortable-CwDHC3CA.js.map +0 -1
- package/dist/chunks/table-BYA0hCj7.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./ui.module-BisoTevy.js";
|
|
2
|
-
import { c as t, n, o as r, r as i } from "./Input-
|
|
2
|
+
import { c as t, n, o as r, r as i } from "./Input-Wrew1puH.js";
|
|
3
3
|
import { cn as a } from "@ryuzaki13/react-foundation-lib/utils";
|
|
4
4
|
import { jsx as o } from "react/jsx-runtime";
|
|
5
5
|
import { useCallback as s, useMemo as c, useRef as l, useState as u } from "react";
|
|
@@ -255,4 +255,4 @@ function w({ mask: e = "YYYY.MM.DD hh:mm", ...t }) {
|
|
|
255
255
|
//#endregion
|
|
256
256
|
export { w as n, C as r, S as t };
|
|
257
257
|
|
|
258
|
-
//# sourceMappingURL=InputDateTime-
|
|
258
|
+
//# sourceMappingURL=InputDateTime-2PCX8an8.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputDateTime-DPtY_4Od.js","names":[],"sources":["../../src/input-date-time/InputDateTime.module.scss","../../src/input-date-time/maskParser.ts","../../src/input-date-time/useMaskedSegments.ts","../../src/input-date-time/InputDateTime.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.segmentInput {\n\tborder: none;\n\tbackground: transparent;\n\toutline: none;\n\tpadding: 0;\n\tmargin: 0;\n\tfont-family: var(--font-family-mono);\n\tcolor: inherit;\n\ttext-align: center;\n\tcaret-color: var(--content-0);\n\tfont-variant-numeric: tabular-nums;\n\n\t&::placeholder {\n\t\tcolor: var(--content-2);\n\t\t// font-size: var(--font-size-sm);\n\t}\n\n\t&::selection {\n\t\tbackground-color: var(--focus-ring);\n\t\tcolor: var(--surface-0);\n\t}\n\n\t// Remove spin buttons\n\t&::-webkit-inner-spin-button,\n\t&::-webkit-outer-spin-button {\n\t\t-webkit-appearance: none;\n\t\tmargin: 0;\n\t}\n\n\t&:disabled {\n\t\topacity: 0.25;\n\t}\n}\n\n.separator {\n\tuser-select: none;\n\tcolor: var(--content-2);\n\tflex-shrink: 0;\n\n\t&[data-disabled] {\n\t\topacity: 0.25;\n\t}\n}\n","import {\n\ttype DateMaskSegment,\n\ttype DateSegmentId,\n\tdateToIndexedSegmentValues,\n\ttype EditableDateSegment,\n\tindexedSegmentsToDate,\n\ttype LiteralDateSegment,\n\tparseDateSegmentMask\n} from \"@ryuzaki13/react-foundation-lib/date-segments\";\n\n/**\n * Совместимый тип сегмента для существующего `InputDateTime`.\n */\nexport type SegmentType = DateSegmentId;\n\n/**\n * Совместимый редактируемый сегмент для существующего `InputDateTime`.\n */\nexport interface EditableSegment extends Omit<EditableDateSegment, \"id\"> {\n\ttype: SegmentType;\n}\n\n/**\n * Совместимый литеральный сегмент для существующего `InputDateTime`.\n */\nexport type LiteralSegment = LiteralDateSegment;\n\n/**\n * Совместимый тип сегмента маски для существующего `InputDateTime`.\n */\nexport type Segment = EditableSegment | LiteralSegment;\n\n/**\n * Разбирает строковую маску, сохраняя прежний контракт `InputDateTime`.\n */\nexport function parseMask(mask: string): Segment[] {\n\treturn parseDateSegmentMask(mask).map((segment) => (segment.kind === \"editable\" ? { ...segment, type: segment.id } : segment));\n}\n\n/**\n * Преобразует Date в карту значений сегментов по их совместимым типам.\n */\nexport function dateToSegmentValues(date: Date | undefined, segments: Segment[]): Map<SegmentType, string> {\n\tconst indexedValues = dateToIndexedSegmentValues(date, segments as DateMaskSegment[]);\n\tconst values = new Map<SegmentType, string>();\n\n\tsegments.forEach((segment, index) => {\n\t\tif (segment.kind !== \"editable\") return;\n\t\tvalues.set(segment.type, indexedValues.get(index) ?? \"\");\n\t});\n\n\treturn values;\n}\n\n/**\n * Собирает строгий Date из карты сегментов старого формата.\n */\nexport function segmentsToDate(segments: Segment[], values: Map<SegmentType, string>): Date | null {\n\tconst indexedValues = new Map<number, string>();\n\n\tsegments.forEach((segment, index) => {\n\t\tif (segment.kind !== \"editable\") return;\n\t\tindexedValues.set(index, values.get(segment.type) ?? \"\");\n\t});\n\n\treturn indexedSegmentsToDate(segments as DateMaskSegment[], indexedValues);\n}\n","import React, { useCallback, useMemo, useRef, useState } from \"react\";\n\nimport { dateToSegmentValues, EditableSegment, parseMask, segmentsToDate, SegmentType } from \"./maskParser\";\n\ninterface UseMaskedSegmentsOptions {\n\tmask: string;\n\tvalue: Date | undefined;\n\tonChange: (date: Date) => void;\n\tonClearError?: () => void;\n\tdisabled?: boolean;\n}\n\n// Вычисляет Map<index, string> из Date и массива сегментов\nfunction buildSegmentMap(date: Date | undefined, segments: ReturnType<typeof parseMask>): Map<number, string> {\n\tconst typeValues = dateToSegmentValues(date, segments);\n\tconst map = new Map<number, string>();\n\n\tsegments.forEach((seg, i) => {\n\t\tif (seg.kind === \"editable\") {\n\t\t\tmap.set(i, typeValues.get(seg.type) ?? \"\");\n\t\t}\n\t});\n\n\treturn map;\n}\n\n// TODO: Duplicate date-time-input/model/useDateTimeSegments\nfunction resolveEditableIndices(segments: ReturnType<typeof parseMask>): number[] {\n\tconst indices: number[] = [];\n\n\tsegments.forEach((segment, index) => {\n\t\tif (segment.kind === \"editable\") {\n\t\t\tindices.push(index);\n\t\t}\n\t});\n\n\treturn indices;\n}\n\nexport function useMaskedSegments({ mask, value, onChange, onClearError, disabled }: UseMaskedSegmentsOptions) {\n\tconst segments = useMemo(() => parseMask(mask), [mask]);\n\n\tconst editableIndices = useMemo(() => resolveEditableIndices(segments), [segments]);\n\n\t// Значения сегментов, вычисленные из пропса value (источник истины)\n\tconst committedValues = useMemo(() => buildSegmentMap(value, segments), [value, segments]);\n\n\t// Локальные «грязные» значения при редактировании (null → используем committedValues)\n\tconst [dirtyValues, setDirtyValues] = useState<Map<number, string> | null>(null);\n\n\t// Сброс грязного состояния при внешнем изменении value (паттерн «adjusting state during render»)\n\tconst [prevValueTime, setPrevValueTime] = useState(() => value?.getTime());\n\tconst currentValueTime = value?.getTime();\n\tif (currentValueTime !== prevValueTime) {\n\t\tsetPrevValueTime(currentValueTime);\n\t\tsetDirtyValues(null);\n\t}\n\n\t// Текущие отображаемые значения\n\tconst segmentValues = dirtyValues ?? committedValues;\n\n\tconst refsMap = useRef<Map<number, HTMLInputElement>>(new Map());\n\tconst blurTimeout = useRef<number>(0);\n\tconst [isFocused, setIsFocused] = useState(false);\n\n\tconst tryFireOnChange = useCallback(\n\t\t(updatedValues: Map<number, string>) => {\n\t\t\tconst typeValues = new Map<SegmentType, string>();\n\n\t\t\tsegments.forEach((seg, i) => {\n\t\t\t\tif (seg.kind === \"editable\") {\n\t\t\t\t\ttypeValues.set(seg.type, updatedValues.get(i) ?? \"\");\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst date = segmentsToDate(segments, typeValues);\n\t\t\tif (date !== null) {\n\t\t\t\tonChange(date);\n\t\t\t}\n\t\t},\n\t\t[segments, onChange]\n\t);\n\n\tconst focusSegment = useCallback((index: number, selectAll = true) => {\n\t\tconst el = refsMap.current.get(index);\n\t\tif (el) {\n\t\t\tel.focus();\n\t\t\tif (selectAll) {\n\t\t\t\trequestAnimationFrame(() => el.select());\n\t\t\t}\n\t\t}\n\t}, []);\n\n\tconst getNextEditable = useCallback(\n\t\t(currentIndex: number): number | null => {\n\t\t\tconst pos = editableIndices.indexOf(currentIndex);\n\t\t\treturn pos < editableIndices.length - 1 ? editableIndices[pos + 1] : null;\n\t\t},\n\t\t[editableIndices]\n\t);\n\n\tconst getPrevEditable = useCallback(\n\t\t(currentIndex: number): number | null => {\n\t\t\tconst pos = editableIndices.indexOf(currentIndex);\n\t\t\treturn pos > 0 ? editableIndices[pos - 1] : null;\n\t\t},\n\t\t[editableIndices]\n\t);\n\n\tconst padValue = useCallback((val: string, segment: EditableSegment): string => {\n\t\treturn val.padStart(segment.length, \"0\");\n\t}, []);\n\n\tconst registerRef = useCallback(\n\t\t(index: number) => (el: HTMLInputElement | null) => {\n\t\t\tif (el) {\n\t\t\t\trefsMap.current.set(index, el);\n\t\t\t} else {\n\t\t\t\trefsMap.current.delete(index);\n\t\t\t}\n\t\t},\n\t\t[]\n\t);\n\n\tconst handleInput = useCallback(\n\t\t(index: number) => (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (disabled) return;\n\n\t\t\tconst segment = segments[index] as EditableSegment;\n\t\t\tconst raw = e.target.value.replace(/\\D/g, \"\");\n\t\t\tconst clamped = raw.slice(0, segment.length);\n\n\t\t\tconst updated = new Map(segmentValues);\n\t\t\tupdated.set(index, clamped);\n\t\t\tsetDirtyValues(updated);\n\n\t\t\tonClearError?.();\n\n\t\t\t// Авто-переход к следующему сегменту при заполнении текущего\n\t\t\tif (clamped.length === segment.length) {\n\t\t\t\tconst next = getNextEditable(index);\n\t\t\t\tif (next !== null) {\n\t\t\t\t\trequestAnimationFrame(() => focusSegment(next));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttryFireOnChange(updated);\n\t\t},\n\t\t[disabled, segments, segmentValues, onClearError, getNextEditable, focusSegment, tryFireOnChange]\n\t);\n\n\tconst handleKeyDown = useCallback(\n\t\t(index: number) => (e: React.KeyboardEvent<HTMLInputElement>) => {\n\t\t\tif (disabled) return;\n\n\t\t\tconst segment = segments[index] as EditableSegment;\n\t\t\tconst currentVal = segmentValues.get(index) ?? \"\";\n\t\t\tconst el = e.currentTarget;\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase \"ArrowRight\": {\n\t\t\t\t\tif (el.selectionStart === currentVal.length || currentVal === \"\") {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tconst next = getNextEditable(index);\n\t\t\t\t\t\tif (next !== null) focusSegment(next);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"ArrowLeft\": {\n\t\t\t\t\tif (el.selectionStart === 0 || currentVal === \"\") {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tconst prev = getPrevEditable(index);\n\t\t\t\t\t\tif (prev !== null) focusSegment(prev);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"ArrowUp\": {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tlet num = currentVal === \"\" ? segment.min : parseInt(currentVal, 10) + 1;\n\t\t\t\t\tif (num > segment.max) num = segment.min;\n\n\t\t\t\t\tconst padded = padValue(num.toString(), segment);\n\t\t\t\t\tconst updated = new Map(segmentValues);\n\t\t\t\t\tupdated.set(index, padded);\n\t\t\t\t\tsetDirtyValues(updated);\n\t\t\t\t\ttryFireOnChange(updated);\n\n\t\t\t\t\trequestAnimationFrame(() => el.select());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"ArrowDown\": {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tlet num = currentVal === \"\" ? segment.max : parseInt(currentVal, 10) - 1;\n\t\t\t\t\tif (num < segment.min) num = segment.max;\n\n\t\t\t\t\tconst padded = padValue(num.toString(), segment);\n\t\t\t\t\tconst updated = new Map(segmentValues);\n\t\t\t\t\tupdated.set(index, padded);\n\t\t\t\t\tsetDirtyValues(updated);\n\t\t\t\t\ttryFireOnChange(updated);\n\n\t\t\t\t\trequestAnimationFrame(() => el.select());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"Backspace\": {\n\t\t\t\t\tif (currentVal === \"\") {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tconst prev = getPrevEditable(index);\n\t\t\t\t\t\tif (prev !== null) focusSegment(prev);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"Delete\": {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tconst updated = new Map(segmentValues);\n\t\t\t\t\tupdated.set(index, \"\");\n\t\t\t\t\tsetDirtyValues(updated);\n\t\t\t\t\ttryFireOnChange(updated);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[disabled, segments, segmentValues, getNextEditable, getPrevEditable, focusSegment, padValue, tryFireOnChange]\n\t);\n\n\tconst handleFocus = useCallback(\n\t\t() => (e: React.FocusEvent<HTMLInputElement>) => {\n\t\t\te.target.select();\n\t\t},\n\t\t[]\n\t);\n\n\tconst handleContainerFocus = useCallback(() => {\n\t\tclearTimeout(blurTimeout.current);\n\t\tsetIsFocused(true);\n\t}, []);\n\n\tconst handleContainerBlur = useCallback(() => {\n\t\tblurTimeout.current = window.setTimeout(() => {\n\t\t\tsetIsFocused(false);\n\t\t\t// Откат к последнему валидному значению (из пропса) при потере фокуса\n\t\t\tsetDirtyValues(null);\n\t\t}, 0);\n\t}, []);\n\n\tconst focusFirstEmpty = useCallback(() => {\n\t\tconst firstEmpty = editableIndices.find((i) => !(segmentValues.get(i) ?? \"\"));\n\t\tconst target = firstEmpty ?? editableIndices[editableIndices.length - 1];\n\t\tif (target !== undefined) focusSegment(target);\n\t}, [editableIndices, segmentValues, focusSegment]);\n\n\treturn {\n\t\tsegments,\n\t\tsegmentValues,\n\t\tisFocused,\n\t\tregisterRef,\n\t\thandleInput,\n\t\thandleKeyDown,\n\t\thandleFocus,\n\t\thandleContainerFocus,\n\t\thandleContainerBlur,\n\t\tfocusFirstEmpty\n\t};\n}\n","import { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { InputClearButton, InputControl, InputUI, useInputFieldIds } from \"../input\";\nimport { UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./InputDateTime.module.scss\";\nimport { useMaskedSegments } from \"./useMaskedSegments\";\n\ninterface InputDateTimeBaseProps extends UiBaseProps<Date, Date | undefined> {\n\tmask: string;\n\n\tclassName?: string;\n\n\terror?: string;\n\tonClearError?: () => void;\n\tonClear?: () => void;\n\n\t\"aria-label\"?: string;\n}\n\nfunction InputDateTimeBase({\n\tmask,\n\tvalue,\n\tonChange,\n\tlabel,\n\tdescription,\n\tdisabled,\n\tsize,\n\tclassName,\n\terror,\n\tonClearError,\n\tonClear,\n\t\"aria-label\": ariaLabel\n}: InputDateTimeBaseProps) {\n\tconst {\n\t\tsegments,\n\t\tsegmentValues,\n\t\tregisterRef,\n\t\thandleInput,\n\t\thandleKeyDown,\n\t\thandleFocus,\n\t\thandleContainerFocus,\n\t\thandleContainerBlur,\n\t\tfocusFirstEmpty\n\t} = useMaskedSegments({ mask, value, onChange, onClearError, disabled });\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={onClear ? <InputClearButton onClick={onClear} disabled={disabled} /> : undefined}\n\t\t\t\tendAdornmentWidth={onClear ? \"var(--control-height)\" : undefined}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControlFake, controlClassName)}\n\t\t\t\t\t\tdata-invalid={error ? \"\" : undefined}\n\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\trole=\"group\"\n\t\t\t\t\t\taria-invalid={!!error || undefined}\n\t\t\t\t\t\taria-label={ariaLabel || (typeof label === \"string\" ? label : undefined)}\n\t\t\t\t\t\taria-labelledby={ariaLabel ? undefined : labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tonFocus={handleContainerFocus}\n\t\t\t\t\t\tonBlur={handleContainerBlur}\n\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\tif (e.target === e.currentTarget) focusFirstEmpty();\n\t\t\t\t\t\t}}>\n\t\t\t\t\t\t{segments.map((segment, index) => {\n\t\t\t\t\t\t\tif (segment.kind === \"literal\") {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<span key={index} className={styles.separator} data-disabled={disabled || undefined}>\n\t\t\t\t\t\t\t\t\t\t{segment.text}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\t\tref={registerRef(index)}\n\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\tinputMode=\"numeric\"\n\t\t\t\t\t\t\t\t\tclassName={styles.segmentInput}\n\t\t\t\t\t\t\t\t\tstyle={{ width: `${segment.length + 0.5}ch` }}\n\t\t\t\t\t\t\t\t\tvalue={segmentValues.get(index) ?? \"\"}\n\t\t\t\t\t\t\t\t\tplaceholder={segment.placeholder}\n\t\t\t\t\t\t\t\t\tmaxLength={segment.length}\n\t\t\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\t\t\taria-label={segment.type}\n\t\t\t\t\t\t\t\t\tautoComplete=\"off\"\n\t\t\t\t\t\t\t\t\tonChange={handleInput(index)}\n\t\t\t\t\t\t\t\t\tonKeyDown={handleKeyDown(index)}\n\t\t\t\t\t\t\t\t\tonFocus={handleFocus()}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\nexport type InputDateProps = Omit<InputDateTimeBaseProps, \"mask\"> & { mask?: string };\nexport type InputTimeProps = Omit<InputDateTimeBaseProps, \"mask\"> & { mask?: string };\nexport type InputDateTimeProps = Omit<InputDateTimeBaseProps, \"mask\"> & { mask?: string };\n\nexport function InputDate({ mask = \"YYYY.MM.DD\", ...props }: InputDateProps) {\n\treturn <InputDateTimeBase mask={mask} {...props} />;\n}\n\nexport function InputTime({ mask = \"hh:mm\", ...props }: InputTimeProps) {\n\treturn <InputDateTimeBase mask={mask} {...props} />;\n}\n\nexport function InputDateTime({ mask = \"YYYY.MM.DD hh:mm\", ...props }: InputDateTimeProps) {\n\treturn <InputDateTimeBase mask={mask} {...props} />;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InputDateTime-2PCX8an8.js","names":[],"sources":["../../src/input-date-time/InputDateTime.module.scss","../../src/input-date-time/maskParser.ts","../../src/input-date-time/useMaskedSegments.ts","../../src/input-date-time/InputDateTime.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.segmentInput {\n\tborder: none;\n\tbackground: transparent;\n\toutline: none;\n\tpadding: 0;\n\tmargin: 0;\n\tfont-family: var(--font-family-mono);\n\tcolor: inherit;\n\ttext-align: center;\n\tcaret-color: var(--content-0);\n\tfont-variant-numeric: tabular-nums;\n\n\t&::placeholder {\n\t\tcolor: var(--content-2);\n\t\t// font-size: var(--font-size-sm);\n\t}\n\n\t&::selection {\n\t\tbackground-color: var(--focus-ring);\n\t\tcolor: var(--surface-0);\n\t}\n\n\t// Remove spin buttons\n\t&::-webkit-inner-spin-button,\n\t&::-webkit-outer-spin-button {\n\t\t-webkit-appearance: none;\n\t\tmargin: 0;\n\t}\n\n\t&:disabled {\n\t\topacity: 0.25;\n\t}\n}\n\n.separator {\n\tuser-select: none;\n\tcolor: var(--content-2);\n\tflex-shrink: 0;\n\n\t&[data-disabled] {\n\t\topacity: 0.25;\n\t}\n}\n","import {\n\ttype DateMaskSegment,\n\ttype DateSegmentId,\n\tdateToIndexedSegmentValues,\n\ttype EditableDateSegment,\n\tindexedSegmentsToDate,\n\ttype LiteralDateSegment,\n\tparseDateSegmentMask\n} from \"@ryuzaki13/react-foundation-lib/date-segments\";\n\n/**\n * Совместимый тип сегмента для существующего `InputDateTime`.\n */\nexport type SegmentType = DateSegmentId;\n\n/**\n * Совместимый редактируемый сегмент для существующего `InputDateTime`.\n */\nexport interface EditableSegment extends Omit<EditableDateSegment, \"id\"> {\n\ttype: SegmentType;\n}\n\n/**\n * Совместимый литеральный сегмент для существующего `InputDateTime`.\n */\nexport type LiteralSegment = LiteralDateSegment;\n\n/**\n * Совместимый тип сегмента маски для существующего `InputDateTime`.\n */\nexport type Segment = EditableSegment | LiteralSegment;\n\n/**\n * Разбирает строковую маску, сохраняя прежний контракт `InputDateTime`.\n */\nexport function parseMask(mask: string): Segment[] {\n\treturn parseDateSegmentMask(mask).map((segment) => (segment.kind === \"editable\" ? { ...segment, type: segment.id } : segment));\n}\n\n/**\n * Преобразует Date в карту значений сегментов по их совместимым типам.\n */\nexport function dateToSegmentValues(date: Date | undefined, segments: Segment[]): Map<SegmentType, string> {\n\tconst indexedValues = dateToIndexedSegmentValues(date, segments as DateMaskSegment[]);\n\tconst values = new Map<SegmentType, string>();\n\n\tsegments.forEach((segment, index) => {\n\t\tif (segment.kind !== \"editable\") return;\n\t\tvalues.set(segment.type, indexedValues.get(index) ?? \"\");\n\t});\n\n\treturn values;\n}\n\n/**\n * Собирает строгий Date из карты сегментов старого формата.\n */\nexport function segmentsToDate(segments: Segment[], values: Map<SegmentType, string>): Date | null {\n\tconst indexedValues = new Map<number, string>();\n\n\tsegments.forEach((segment, index) => {\n\t\tif (segment.kind !== \"editable\") return;\n\t\tindexedValues.set(index, values.get(segment.type) ?? \"\");\n\t});\n\n\treturn indexedSegmentsToDate(segments as DateMaskSegment[], indexedValues);\n}\n","import React, { useCallback, useMemo, useRef, useState } from \"react\";\n\nimport { dateToSegmentValues, EditableSegment, parseMask, segmentsToDate, SegmentType } from \"./maskParser\";\n\ninterface UseMaskedSegmentsOptions {\n\tmask: string;\n\tvalue: Date | undefined;\n\tonChange: (date: Date) => void;\n\tonClearError?: () => void;\n\tdisabled?: boolean;\n}\n\n// Вычисляет Map<index, string> из Date и массива сегментов\nfunction buildSegmentMap(date: Date | undefined, segments: ReturnType<typeof parseMask>): Map<number, string> {\n\tconst typeValues = dateToSegmentValues(date, segments);\n\tconst map = new Map<number, string>();\n\n\tsegments.forEach((seg, i) => {\n\t\tif (seg.kind === \"editable\") {\n\t\t\tmap.set(i, typeValues.get(seg.type) ?? \"\");\n\t\t}\n\t});\n\n\treturn map;\n}\n\n// TODO: Duplicate date-time-input/model/useDateTimeSegments\nfunction resolveEditableIndices(segments: ReturnType<typeof parseMask>): number[] {\n\tconst indices: number[] = [];\n\n\tsegments.forEach((segment, index) => {\n\t\tif (segment.kind === \"editable\") {\n\t\t\tindices.push(index);\n\t\t}\n\t});\n\n\treturn indices;\n}\n\nexport function useMaskedSegments({ mask, value, onChange, onClearError, disabled }: UseMaskedSegmentsOptions) {\n\tconst segments = useMemo(() => parseMask(mask), [mask]);\n\n\tconst editableIndices = useMemo(() => resolveEditableIndices(segments), [segments]);\n\n\t// Значения сегментов, вычисленные из пропса value (источник истины)\n\tconst committedValues = useMemo(() => buildSegmentMap(value, segments), [value, segments]);\n\n\t// Локальные «грязные» значения при редактировании (null → используем committedValues)\n\tconst [dirtyValues, setDirtyValues] = useState<Map<number, string> | null>(null);\n\n\t// Сброс грязного состояния при внешнем изменении value (паттерн «adjusting state during render»)\n\tconst [prevValueTime, setPrevValueTime] = useState(() => value?.getTime());\n\tconst currentValueTime = value?.getTime();\n\tif (currentValueTime !== prevValueTime) {\n\t\tsetPrevValueTime(currentValueTime);\n\t\tsetDirtyValues(null);\n\t}\n\n\t// Текущие отображаемые значения\n\tconst segmentValues = dirtyValues ?? committedValues;\n\n\tconst refsMap = useRef<Map<number, HTMLInputElement>>(new Map());\n\tconst blurTimeout = useRef<number>(0);\n\tconst [isFocused, setIsFocused] = useState(false);\n\n\tconst tryFireOnChange = useCallback(\n\t\t(updatedValues: Map<number, string>) => {\n\t\t\tconst typeValues = new Map<SegmentType, string>();\n\n\t\t\tsegments.forEach((seg, i) => {\n\t\t\t\tif (seg.kind === \"editable\") {\n\t\t\t\t\ttypeValues.set(seg.type, updatedValues.get(i) ?? \"\");\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst date = segmentsToDate(segments, typeValues);\n\t\t\tif (date !== null) {\n\t\t\t\tonChange(date);\n\t\t\t}\n\t\t},\n\t\t[segments, onChange]\n\t);\n\n\tconst focusSegment = useCallback((index: number, selectAll = true) => {\n\t\tconst el = refsMap.current.get(index);\n\t\tif (el) {\n\t\t\tel.focus();\n\t\t\tif (selectAll) {\n\t\t\t\trequestAnimationFrame(() => el.select());\n\t\t\t}\n\t\t}\n\t}, []);\n\n\tconst getNextEditable = useCallback(\n\t\t(currentIndex: number): number | null => {\n\t\t\tconst pos = editableIndices.indexOf(currentIndex);\n\t\t\treturn pos < editableIndices.length - 1 ? editableIndices[pos + 1] : null;\n\t\t},\n\t\t[editableIndices]\n\t);\n\n\tconst getPrevEditable = useCallback(\n\t\t(currentIndex: number): number | null => {\n\t\t\tconst pos = editableIndices.indexOf(currentIndex);\n\t\t\treturn pos > 0 ? editableIndices[pos - 1] : null;\n\t\t},\n\t\t[editableIndices]\n\t);\n\n\tconst padValue = useCallback((val: string, segment: EditableSegment): string => {\n\t\treturn val.padStart(segment.length, \"0\");\n\t}, []);\n\n\tconst registerRef = useCallback(\n\t\t(index: number) => (el: HTMLInputElement | null) => {\n\t\t\tif (el) {\n\t\t\t\trefsMap.current.set(index, el);\n\t\t\t} else {\n\t\t\t\trefsMap.current.delete(index);\n\t\t\t}\n\t\t},\n\t\t[]\n\t);\n\n\tconst handleInput = useCallback(\n\t\t(index: number) => (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (disabled) return;\n\n\t\t\tconst segment = segments[index] as EditableSegment;\n\t\t\tconst raw = e.target.value.replace(/\\D/g, \"\");\n\t\t\tconst clamped = raw.slice(0, segment.length);\n\n\t\t\tconst updated = new Map(segmentValues);\n\t\t\tupdated.set(index, clamped);\n\t\t\tsetDirtyValues(updated);\n\n\t\t\tonClearError?.();\n\n\t\t\t// Авто-переход к следующему сегменту при заполнении текущего\n\t\t\tif (clamped.length === segment.length) {\n\t\t\t\tconst next = getNextEditable(index);\n\t\t\t\tif (next !== null) {\n\t\t\t\t\trequestAnimationFrame(() => focusSegment(next));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttryFireOnChange(updated);\n\t\t},\n\t\t[disabled, segments, segmentValues, onClearError, getNextEditable, focusSegment, tryFireOnChange]\n\t);\n\n\tconst handleKeyDown = useCallback(\n\t\t(index: number) => (e: React.KeyboardEvent<HTMLInputElement>) => {\n\t\t\tif (disabled) return;\n\n\t\t\tconst segment = segments[index] as EditableSegment;\n\t\t\tconst currentVal = segmentValues.get(index) ?? \"\";\n\t\t\tconst el = e.currentTarget;\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase \"ArrowRight\": {\n\t\t\t\t\tif (el.selectionStart === currentVal.length || currentVal === \"\") {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tconst next = getNextEditable(index);\n\t\t\t\t\t\tif (next !== null) focusSegment(next);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"ArrowLeft\": {\n\t\t\t\t\tif (el.selectionStart === 0 || currentVal === \"\") {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tconst prev = getPrevEditable(index);\n\t\t\t\t\t\tif (prev !== null) focusSegment(prev);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"ArrowUp\": {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tlet num = currentVal === \"\" ? segment.min : parseInt(currentVal, 10) + 1;\n\t\t\t\t\tif (num > segment.max) num = segment.min;\n\n\t\t\t\t\tconst padded = padValue(num.toString(), segment);\n\t\t\t\t\tconst updated = new Map(segmentValues);\n\t\t\t\t\tupdated.set(index, padded);\n\t\t\t\t\tsetDirtyValues(updated);\n\t\t\t\t\ttryFireOnChange(updated);\n\n\t\t\t\t\trequestAnimationFrame(() => el.select());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"ArrowDown\": {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tlet num = currentVal === \"\" ? segment.max : parseInt(currentVal, 10) - 1;\n\t\t\t\t\tif (num < segment.min) num = segment.max;\n\n\t\t\t\t\tconst padded = padValue(num.toString(), segment);\n\t\t\t\t\tconst updated = new Map(segmentValues);\n\t\t\t\t\tupdated.set(index, padded);\n\t\t\t\t\tsetDirtyValues(updated);\n\t\t\t\t\ttryFireOnChange(updated);\n\n\t\t\t\t\trequestAnimationFrame(() => el.select());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"Backspace\": {\n\t\t\t\t\tif (currentVal === \"\") {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tconst prev = getPrevEditable(index);\n\t\t\t\t\t\tif (prev !== null) focusSegment(prev);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"Delete\": {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tconst updated = new Map(segmentValues);\n\t\t\t\t\tupdated.set(index, \"\");\n\t\t\t\t\tsetDirtyValues(updated);\n\t\t\t\t\ttryFireOnChange(updated);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[disabled, segments, segmentValues, getNextEditable, getPrevEditable, focusSegment, padValue, tryFireOnChange]\n\t);\n\n\tconst handleFocus = useCallback(\n\t\t() => (e: React.FocusEvent<HTMLInputElement>) => {\n\t\t\te.target.select();\n\t\t},\n\t\t[]\n\t);\n\n\tconst handleContainerFocus = useCallback(() => {\n\t\tclearTimeout(blurTimeout.current);\n\t\tsetIsFocused(true);\n\t}, []);\n\n\tconst handleContainerBlur = useCallback(() => {\n\t\tblurTimeout.current = window.setTimeout(() => {\n\t\t\tsetIsFocused(false);\n\t\t\t// Откат к последнему валидному значению (из пропса) при потере фокуса\n\t\t\tsetDirtyValues(null);\n\t\t}, 0);\n\t}, []);\n\n\tconst focusFirstEmpty = useCallback(() => {\n\t\tconst firstEmpty = editableIndices.find((i) => !(segmentValues.get(i) ?? \"\"));\n\t\tconst target = firstEmpty ?? editableIndices[editableIndices.length - 1];\n\t\tif (target !== undefined) focusSegment(target);\n\t}, [editableIndices, segmentValues, focusSegment]);\n\n\treturn {\n\t\tsegments,\n\t\tsegmentValues,\n\t\tisFocused,\n\t\tregisterRef,\n\t\thandleInput,\n\t\thandleKeyDown,\n\t\thandleFocus,\n\t\thandleContainerFocus,\n\t\thandleContainerBlur,\n\t\tfocusFirstEmpty\n\t};\n}\n","import { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { InputClearButton, InputControl, InputUI, useInputFieldIds } from \"../input\";\nimport { UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./InputDateTime.module.scss\";\nimport { useMaskedSegments } from \"./useMaskedSegments\";\n\ninterface InputDateTimeBaseProps extends UiBaseProps<Date, Date | undefined> {\n\tmask: string;\n\n\tclassName?: string;\n\n\terror?: string;\n\tonClearError?: () => void;\n\tonClear?: () => void;\n\n\t\"aria-label\"?: string;\n}\n\nfunction InputDateTimeBase({\n\tmask,\n\tvalue,\n\tonChange,\n\tlabel,\n\tdescription,\n\tdisabled,\n\tsize,\n\tclassName,\n\terror,\n\tonClearError,\n\tonClear,\n\t\"aria-label\": ariaLabel\n}: InputDateTimeBaseProps) {\n\tconst {\n\t\tsegments,\n\t\tsegmentValues,\n\t\tregisterRef,\n\t\thandleInput,\n\t\thandleKeyDown,\n\t\thandleFocus,\n\t\thandleContainerFocus,\n\t\thandleContainerBlur,\n\t\tfocusFirstEmpty\n\t} = useMaskedSegments({ mask, value, onChange, onClearError, disabled });\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={onClear ? <InputClearButton onClick={onClear} disabled={disabled} /> : undefined}\n\t\t\t\tendAdornmentWidth={onClear ? \"var(--control-height)\" : undefined}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControlFake, controlClassName)}\n\t\t\t\t\t\tdata-invalid={error ? \"\" : undefined}\n\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\trole=\"group\"\n\t\t\t\t\t\taria-invalid={!!error || undefined}\n\t\t\t\t\t\taria-label={ariaLabel || (typeof label === \"string\" ? label : undefined)}\n\t\t\t\t\t\taria-labelledby={ariaLabel ? undefined : labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tonFocus={handleContainerFocus}\n\t\t\t\t\t\tonBlur={handleContainerBlur}\n\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\tif (e.target === e.currentTarget) focusFirstEmpty();\n\t\t\t\t\t\t}}>\n\t\t\t\t\t\t{segments.map((segment, index) => {\n\t\t\t\t\t\t\tif (segment.kind === \"literal\") {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<span key={index} className={styles.separator} data-disabled={disabled || undefined}>\n\t\t\t\t\t\t\t\t\t\t{segment.text}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\t\tref={registerRef(index)}\n\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\tinputMode=\"numeric\"\n\t\t\t\t\t\t\t\t\tclassName={styles.segmentInput}\n\t\t\t\t\t\t\t\t\tstyle={{ width: `${segment.length + 0.5}ch` }}\n\t\t\t\t\t\t\t\t\tvalue={segmentValues.get(index) ?? \"\"}\n\t\t\t\t\t\t\t\t\tplaceholder={segment.placeholder}\n\t\t\t\t\t\t\t\t\tmaxLength={segment.length}\n\t\t\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\t\t\taria-label={segment.type}\n\t\t\t\t\t\t\t\t\tautoComplete=\"off\"\n\t\t\t\t\t\t\t\t\tonChange={handleInput(index)}\n\t\t\t\t\t\t\t\t\tonKeyDown={handleKeyDown(index)}\n\t\t\t\t\t\t\t\t\tonFocus={handleFocus()}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\nexport type InputDateProps = Omit<InputDateTimeBaseProps, \"mask\"> & { mask?: string };\nexport type InputTimeProps = Omit<InputDateTimeBaseProps, \"mask\"> & { mask?: string };\nexport type InputDateTimeProps = Omit<InputDateTimeBaseProps, \"mask\"> & { mask?: string };\n\nexport function InputDate({ mask = \"YYYY.MM.DD\", ...props }: InputDateProps) {\n\treturn <InputDateTimeBase mask={mask} {...props} />;\n}\n\nexport function InputTime({ mask = \"hh:mm\", ...props }: InputTimeProps) {\n\treturn <InputDateTimeBase mask={mask} {...props} />;\n}\n\nexport function InputDateTime({ mask = \"YYYY.MM.DD hh:mm\", ...props }: InputDateTimeProps) {\n\treturn <InputDateTimeBase mask={mask} {...props} />;\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./ui.module-BisoTevy.js";
|
|
2
|
-
import { c as t, n, o as r, r as i } from "./Input-
|
|
2
|
+
import { c as t, n, o as r, r as i } from "./Input-Wrew1puH.js";
|
|
3
3
|
import { cn as a, handleKeyboardActivation as o } from "@ryuzaki13/react-foundation-lib/utils";
|
|
4
4
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
5
|
import { useCallback as l, useRef as u } from "react";
|
|
@@ -102,4 +102,4 @@ function g(g) {
|
|
|
102
102
|
//#endregion
|
|
103
103
|
export { g as t };
|
|
104
104
|
|
|
105
|
-
//# sourceMappingURL=InputFile-
|
|
105
|
+
//# sourceMappingURL=InputFile-Ca-bRo93.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputFile-Ca-bRo93.js","names":[],"sources":["../../src/input-file/InputFile.module.scss","../../src/input-file/InputFile.tsx"],"sourcesContent":[".control {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: 0 var(--space-sm);\n\tfont-size: var(--font-size-md);\n\tcursor: pointer;\n\tdisplay: flex;\n\talign-items: center;\n}\n\n.fileName {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.hiddenInput {\n\tposition: absolute;\n\twidth: 0;\n\theight: 0;\n\topacity: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n}\n","import { useCallback, useRef } from \"react\";\n\nimport {\n\tassertValidAccept,\n\tassertValidAllowedMime,\n\treadFile,\n\tReadFileError,\n\tReadFileResult,\n\tReadMode\n} from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn, handleKeyboardActivation } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { InputClearButton, InputControl, InputUI, useInputFieldIds } from \"../input\";\nimport { UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./InputFile.module.scss\";\n\ninterface InputFileCommonProps extends Omit<UiBaseProps<undefined>, \"value\" | \"onChange\"> {\n\t/** Callback очистки выбранного файла. Если передан — отображается кнопка «крестик» */\n\tonClear?: () => void;\n\t/** Callback ошибки чтения файла (невалидный MIME, превышение размера и т.д.) */\n\tonReadError?: (error: ReadFileError) => void;\n\n\t/** HTML-атрибут accept для нативного input[type=\"file\"] (например `[\".pdf\", \".docx\"]`) */\n\taccept?: readonly string[];\n\t/** Список допустимых MIME-типов — передаётся в readFile для валидации */\n\tallowedMime?: readonly string[];\n\t/** Максимальный размер файла в байтах — передаётся в readFile для валидации */\n\tmaxBytes?: number;\n\t/** Режим чтения файла: \"data-url\" (по умолчанию) или \"array-buffer\" */\n\treadMode?: ReadMode;\n\n\t/** Текст ошибки под полем */\n\terror?: string;\n\t/** Callback сброса ошибки (вызывается при повторном выборе файла) */\n\tonClearError?: () => void;\n\t/** CSS-класс обёртки */\n\tclassName?: string;\n}\n\ntype InputFileDataUrlResult = Extract<ReadFileResult, { mode: \"data-url\" }>;\ntype InputFileArrayBufferResult = Extract<ReadFileResult, { mode: \"array-buffer\" }>;\n\n/**\n * Пропсы компонента InputFile.\n *\n * Компонент предназначен для выбора одного файла.\n * Внешний вид идентичен InputText — label, description, error, кнопка очистки.\n *\n * В onChange передаётся результат чтения файла через readFile:\n * - В режиме \"data-url\" — объект с dataUrl и метаданными\n * - В режиме \"array-buffer\" — объект с ArrayBuffer и метаданными\n */\nexport type InputFileProps =\n\t| (InputFileCommonProps & {\n\t\t\tvalue: ReadFileResult | undefined;\n\t\t\tonChange: (value: InputFileDataUrlResult) => void;\n\t\t\treadMode?: \"data-url\";\n\t })\n\t| (InputFileCommonProps & {\n\t\t\tvalue: ReadFileResult | undefined;\n\t\t\tonChange: (value: InputFileArrayBufferResult) => void;\n\t\t\treadMode: \"array-buffer\";\n\t });\n\n/**\n * InputFile — компонент выбора одного файла.\n *\n * Визуально идентичен InputText: поле с label, description, placeholder,\n * кнопкой очистки (крестик) и блоком ошибки.\n *\n * При клике открывается нативный диалог выбора файла.\n * После выбора файл читается через readFile, результат передаётся в onChange.\n *\n * InputFile позволяет выбрать один файл и передаёт наружу типизированный результат чтения.\n * Если `readMode` не задан или равен `\"data-url\"`, в `onChange` приходит объект с `dataUrl`.\n * Если `readMode` равен `\"array-buffer\"`, в `onChange` приходит объект с `buffer`.\n */\nexport function InputFile(props: InputFileProps) {\n\tconst {\n\t\tvalue,\n\t\tonClear,\n\t\tonReadError,\n\t\taccept,\n\t\tallowedMime,\n\t\tmaxBytes,\n\t\tlabel,\n\t\tdescription,\n\t\tplaceholder = \"Выберите файл\",\n\t\tdisabled,\n\t\tsize,\n\t\terror,\n\t\tonClearError,\n\t\tclassName\n\t} = props;\n\n\tassertValidAllowedMime(allowedMime);\n\tassertValidAccept(accept);\n\n\t/** Реф на скрытый нативный input[type=\"file\"] */\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\t/**\n\t * Обработчик выбора файла из нативного диалога.\n\t * Читает файл через readFile и передаёт результат в onChange.\n\t * При ошибке чтения вызывает onReadError.\n\t */\n\tconst handleChange = useCallback(\n\t\tasync (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tconst file = e.target.files?.[0];\n\t\t\tif (!file) return;\n\n\t\t\t// Сбрасываем значение input чтобы можно было выбрать тот же файл повторно\n\t\t\te.target.value = \"\";\n\n\t\t\t// Сбрасываем ошибку при повторном выборе\n\t\t\tif (error && onClearError) onClearError();\n\n\t\t\ttry {\n\t\t\t\tif (props.readMode === \"array-buffer\") {\n\t\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes, mode: \"array-buffer\" });\n\t\t\t\t\tprops.onChange(result);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes });\n\t\t\t\tprops.onChange(result);\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof ReadFileError && onReadError) {\n\t\t\t\t\tonReadError(err);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[props, allowedMime, maxBytes, onReadError, error, onClearError]\n\t);\n\n\t/** Клик по видимому контролу открывает нативный диалог */\n\tconst handleClick = useCallback(() => {\n\t\tinputRef.current?.click();\n\t}, []);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\tid={controlId}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={(accept ?? allowedMime)?.join(\",\")}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tclassName={styles.hiddenInput}\n\t\t\t\tonChange={handleChange}\n\t\t\t\ttabIndex={-1}\n\t\t\t/>\n\n\t\t\t<InputControl\n\t\t\t\tendAdornment={onClear ? <InputClearButton onClick={onClear} disabled={disabled} /> : undefined}\n\t\t\t\tendAdornmentWidth={onClear ? \"var(--control-height)\" : undefined}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\ttabIndex={disabled ? -1 : 0}\n\t\t\t\t\t\tonClick={handleClick}\n\t\t\t\t\t\tonKeyDown={(event) => handleKeyboardActivation(event, handleClick, { disabled })}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.control, controlClassName, !!error && uiStyles.invalid)}\n\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\taria-invalid={!!error || undefined}\n\t\t\t\t\t\taria-disabled={disabled}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}>\n\t\t\t\t\t\t{value ? (\n\t\t\t\t\t\t\t<span className={styles.fileName}>{value.meta.name}</span>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span className={uiStyles.uiPlaceholder}>{placeholder}</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;AC+EA,SAAgB,EAAU,GAAuB;CAChD,IAAM,EACL,UACA,YACA,gBACA,WACA,gBACA,aACA,UACA,gBACA,iBAAc,iBACd,aACA,SACA,UACA,iBACA,iBACG;CAGJ,AADA,EAAuB,CAAW,GAClC,EAAkB,CAAM;CAGxB,IAAM,IAAW,EAAyB,IAAI,GACxC,EAAE,cAAW,YAAS,kBAAe,YAAS,mBAAgB,EAAiB;EACpF,UAAU,KAAiC;EAC3C,gBAAgB,CAAC,CAAC;EAClB,UAAU,CAAC,CAAC;CACb,CAAC,GAOK,IAAe,EACpB,OAAO,MAA2C;EACjD,IAAM,IAAO,EAAE,OAAO,QAAQ;EACzB,OAML;GAHA,EAAE,OAAO,QAAQ,IAGb,KAAS,KAAc,EAAa;GAExC,IAAI;IACH,IAAI,EAAM,aAAa,gBAAgB;KACtC,IAAM,IAAS,MAAM,EAAS,GAAM;MAAE;MAAa;MAAU,MAAM;KAAe,CAAC;KACnF,EAAM,SAAS,CAAM;KACrB;IACD;IAEA,IAAM,IAAS,MAAM,EAAS,GAAM;KAAE;KAAa;IAAS,CAAC;IAC7D,EAAM,SAAS,CAAM;GACtB,SAAS,GAAK;IACb,AAAI,aAAe,KAAiB,KACnC,EAAY,CAAG;GAEjB;EAfwC;CAgBzC,GACA;EAAC;EAAO;EAAa;EAAU;EAAa;EAAO;CAAY,CAChE,GAGM,IAAc,QAAkB;EACrC,EAAS,SAAS,MAAM;CACzB,GAAG,CAAC,CAAC;CAEL,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACC;EACL;EACC;EACI;EACF;EACM;EACN;YAVV,CAWC,kBAAC,SAAD;GACC,KAAK;GACL,IAAI;GACJ,MAAK;GACL,SAAS,KAAU,EAAA,EAAc,KAAK,GAAG;GAC/B;GACV,WAAW,EAAO;GAClB,UAAU;GACV,UAAU;EACV,CAAA,GAED,kBAAC,GAAD;GACC,cAAc,IAAU,kBAAC,GAAD;IAAkB,SAAS;IAAmB;GAAW,CAAA,IAAI,KAAA;GACrF,mBAAmB,IAAU,0BAA0B,KAAA;cACrD,EAAE,0BACH,kBAAC,OAAD;IACC,MAAK;IACL,UAAU,IAAW,KAAK;IAC1B,SAAS;IACT,YAAY,MAAU,EAAyB,GAAO,GAAa,EAAE,YAAS,CAAC;IAC/E,WAAW,EAAG,EAAS,gBAAgB,EAAO,SAAS,GAAkB,CAAC,CAAC,KAAS,EAAS,OAAO;IACpG,iBAAe,KAAY,KAAA;IAC3B,gBAAc,CAAC,CAAC,KAAS,KAAA;IACzB,iBAAe;IACf,mBAAiB;IACjB,oBAAkB;cACjB,IACA,kBAAC,QAAD;KAAM,WAAW,EAAO;eAAW,EAAM,KAAK;IAAW,CAAA,IAEzD,kBAAC,QAAD;KAAM,WAAW,EAAS;eAAgB;IAAkB,CAAA;GAEzD,CAAA;EAEO,CAAA,CACN;;AAEX"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as e } from "./ui.module-BisoTevy.js";
|
|
2
|
-
import { c as t, o as n, r } from "./Input-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { c as t, o as n, r } from "./Input-Wrew1puH.js";
|
|
3
|
+
import { cn as i, handleKeyboardActivation as a } from "@ryuzaki13/react-foundation-lib/utils";
|
|
4
|
+
import { XIcon as o } from "lucide-react";
|
|
5
5
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
6
6
|
import { useCallback as l, useRef as u } from "react";
|
|
7
7
|
import { ReadFileError as d, assertValidAccept as f, assertValidAllowedMime as p, readFile as m } from "@ryuzaki13/react-foundation-lib/file";
|
|
@@ -28,18 +28,18 @@ function g({ files: e, onChange: t }) {
|
|
|
28
28
|
children: e.meta.name
|
|
29
29
|
}), /* @__PURE__ */ s("button", {
|
|
30
30
|
type: "button",
|
|
31
|
-
className:
|
|
31
|
+
className: i(h.removeButton, "flexCenter"),
|
|
32
32
|
onClick: () => n(t),
|
|
33
33
|
"aria-label": `Удалить ${e.meta.name}`,
|
|
34
|
-
children: /* @__PURE__ */ s(
|
|
34
|
+
children: /* @__PURE__ */ s(o, {})
|
|
35
35
|
})]
|
|
36
36
|
}, `${e.meta.name}-${e.meta.lastModified}`))
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/input-files/InputFiles.tsx
|
|
41
|
-
function _(
|
|
42
|
-
let { value: _, onReadError: v, accept: y, allowedMime: b, maxBytes: x, maxFiles: S, label: C, description: w, placeholder: T = "Выберите файлы", disabled: E, size: D, error: O, onClearError: k, className: A } =
|
|
41
|
+
function _(o) {
|
|
42
|
+
let { value: _, onReadError: v, accept: y, allowedMime: b, maxBytes: x, maxFiles: S, label: C, description: w, placeholder: T = "Выберите файлы", disabled: E, size: D, error: O, onClearError: k, className: A } = o;
|
|
43
43
|
p(b), f(y);
|
|
44
44
|
let j = u(null), { controlId: M, labelId: N, descriptionId: P, errorId: F, describedBy: I } = t({
|
|
45
45
|
hasLabel: C != null,
|
|
@@ -50,10 +50,10 @@ function _(i) {
|
|
|
50
50
|
if (!t || t.length === 0) return;
|
|
51
51
|
let n = Array.from(t);
|
|
52
52
|
e.target.value = "", O && k && k();
|
|
53
|
-
let r = typeof S == "number" ? S - _.length : n.length,
|
|
54
|
-
if (
|
|
53
|
+
let r = typeof S == "number" ? S - _.length : n.length, i = n.slice(0, r);
|
|
54
|
+
if (o.readMode === "array-buffer") {
|
|
55
55
|
let e = [];
|
|
56
|
-
for (let t of
|
|
56
|
+
for (let t of i) try {
|
|
57
57
|
let n = await m(t, {
|
|
58
58
|
allowedMime: b,
|
|
59
59
|
maxBytes: x,
|
|
@@ -63,22 +63,22 @@ function _(i) {
|
|
|
63
63
|
} catch (e) {
|
|
64
64
|
e instanceof d && v && v(e);
|
|
65
65
|
}
|
|
66
|
-
e.length > 0 &&
|
|
66
|
+
e.length > 0 && o.onChange([...o.value, ...e]);
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
|
-
let
|
|
70
|
-
for (let e of
|
|
69
|
+
let a = [];
|
|
70
|
+
for (let e of i) try {
|
|
71
71
|
let t = await m(e, {
|
|
72
72
|
allowedMime: b,
|
|
73
73
|
maxBytes: x
|
|
74
74
|
});
|
|
75
|
-
|
|
75
|
+
a.push(t);
|
|
76
76
|
} catch (e) {
|
|
77
77
|
e instanceof d && v && v(e);
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
a.length > 0 && o.onChange([...o.value, ...a]);
|
|
80
80
|
}, [
|
|
81
|
-
|
|
81
|
+
o,
|
|
82
82
|
S,
|
|
83
83
|
_.length,
|
|
84
84
|
b,
|
|
@@ -88,9 +88,9 @@ function _(i) {
|
|
|
88
88
|
k
|
|
89
89
|
]), z = l(() => {
|
|
90
90
|
j.current?.click();
|
|
91
|
-
}, []), B = (
|
|
92
|
-
files:
|
|
93
|
-
onChange:
|
|
91
|
+
}, []), B = (o.readMode, /* @__PURE__ */ s(g, {
|
|
92
|
+
files: o.value,
|
|
93
|
+
onChange: o.onChange
|
|
94
94
|
}));
|
|
95
95
|
return /* @__PURE__ */ c(n, {
|
|
96
96
|
label: C,
|
|
@@ -119,8 +119,8 @@ function _(i) {
|
|
|
119
119
|
role: "button",
|
|
120
120
|
tabIndex: E || L ? -1 : 0,
|
|
121
121
|
onClick: z,
|
|
122
|
-
onKeyDown: (e) =>
|
|
123
|
-
className:
|
|
122
|
+
onKeyDown: (e) => a(e, z, { disabled: E || L }),
|
|
123
|
+
className: i(e.uiInputControl, h.control, !!O && "invalid"),
|
|
124
124
|
"data-disabled": E || void 0,
|
|
125
125
|
"aria-invalid": !!O || void 0,
|
|
126
126
|
"aria-disabled": E || L,
|
|
@@ -138,4 +138,4 @@ function _(i) {
|
|
|
138
138
|
//#endregion
|
|
139
139
|
export { g as n, _ as t };
|
|
140
140
|
|
|
141
|
-
//# sourceMappingURL=InputFiles-
|
|
141
|
+
//# sourceMappingURL=InputFiles-pI9rQXOI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputFiles-pI9rQXOI.js","names":[],"sources":["../../src/input-files/InputFiles.module.scss","../../src/input-files/InputFilesList.tsx","../../src/input-files/InputFiles.tsx"],"sourcesContent":["/* Контрол, имитирующий внешний вид InputText */\n.control {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: 0 var(--space-sm);\n\tfont-size: var(--font-size-md);\n\tcursor: pointer;\n\n\tdisplay: flex;\n\talign-items: center;\n}\n\n/* Скрытый нативный input[type=\"file\"] */\n.hiddenInput {\n\tposition: absolute;\n\twidth: 0;\n\theight: 0;\n\topacity: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n}\n\n/* Список выбранных файлов */\n.fileList {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--space-xs);\n\tmargin-top: var(--space-xs);\n}\n\n/* Элемент списка — строка с именем файла и кнопкой удаления */\n.fileItem {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n\tpadding: var(--space-xs) var(--space-sm);\n\tbackground-color: var(--surface-2);\n\tborder-radius: var(--radius-sm);\n\t// font-size: var(--font-size-sm);\n}\n\n/* Имя файла — обрезка с троеточием */\n.fileItemName {\n\tflex: 1;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n/* Кнопка удаления файла из списка */\n.removeButton {\n\tflex-shrink: 0;\n\twidth: 1.25em;\n\theight: 1.25em;\n\tcolor: var(--content-2);\n\n\t&:hover {\n\t\tcolor: var(--content-accent);\n\t}\n}\n","import { useCallback } from \"react\";\n\nimport { ReadFileResult } from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { XIcon } from \"lucide-react\";\n\nimport styles from \"./InputFiles.module.scss\";\n\ninterface InputFilesListProps<TFile extends ReadFileResult> {\n\tfiles: TFile[];\n\tonChange: (files: TFile[]) => void;\n}\n\nexport function InputFilesList<TFile extends ReadFileResult>({ files, onChange }: InputFilesListProps<TFile>) {\n\tconst handleRemove = useCallback(\n\t\t(index: number) => {\n\t\t\tonChange(files.filter((_, i) => i !== index));\n\t\t},\n\t\t[files, onChange]\n\t);\n\n\tif (!files || !files.length) return null;\n\n\treturn (\n\t\t<ul className={styles.fileList}>\n\t\t\t{files.map((item, index) => (\n\t\t\t\t<li key={`${item.meta.name}-${item.meta.lastModified}`} className={styles.fileItem}>\n\t\t\t\t\t<span className={styles.fileItemName}>{item.meta.name}</span>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName={cn(styles.removeButton, \"flexCenter\")}\n\t\t\t\t\t\tonClick={() => handleRemove(index)}\n\t\t\t\t\t\taria-label={`Удалить ${item.meta.name}`}>\n\t\t\t\t\t\t<XIcon />\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\n","import { useCallback, useRef } from \"react\";\n\nimport { assertValidAccept, assertValidAllowedMime, readFile, ReadFileError, ReadFileResult } from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn, handleKeyboardActivation } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { InputControl, InputUI, useInputFieldIds } from \"../input\";\nimport { UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./InputFiles.module.scss\";\nimport { InputFilesList } from \"./InputFilesList\";\n\ninterface InputFilesCommonProps extends Omit<UiBaseProps<undefined>, \"value\" | \"onChange\"> {\n\t/** Callback ошибки чтения файла */\n\tonReadError?: (error: ReadFileError) => void;\n\n\t/** HTML-атрибут accept для нативного input[type=\"file\"] (например `[\".pdf\", \".docx\"]`) */\n\taccept?: readonly string[];\n\t/** Список допустимых MIME-типов — передаётся в readFile */\n\tallowedMime?: readonly string[];\n\t/** Максимальный размер одного файла в байтах */\n\tmaxBytes?: number;\n\t/** Максимальное количество файлов. При достижении лимита input блокируется */\n\tmaxFiles?: number;\n\n\t/** Текст ошибки под полем */\n\terror?: string;\n\t/** Callback сброса ошибки */\n\tonClearError?: () => void;\n\t/** CSS-класс обёртки */\n\tclassName?: string;\n}\n\ntype InputFilesDataUrlResult = Extract<ReadFileResult, { mode: \"data-url\" }>;\ntype InputFilesArrayBufferResult = Extract<ReadFileResult, { mode: \"array-buffer\" }>;\n\n/**\n * Пропсы компонента InputFiles.\n *\n * Компонент предназначен для выбора нескольких файлов.\n * Выбранные файлы отображаются списком под полем ввода,\n * каждый с кнопкой удаления (крестик).\n *\n * В onChange передаётся обновлённый массив результатов readFile.\n */\nexport type InputFilesProps =\n\t| (InputFilesCommonProps & {\n\t\t\tvalue: InputFilesDataUrlResult[];\n\t\t\tonChange: (value: InputFilesDataUrlResult[]) => void;\n\t\t\t/** Режим чтения: \"data-url\" по умолчанию */\n\t\t\treadMode?: \"data-url\";\n\t })\n\t| (InputFilesCommonProps & {\n\t\t\tvalue: InputFilesArrayBufferResult[];\n\t\t\tonChange: (value: InputFilesArrayBufferResult[]) => void;\n\t\t\t/** Режим чтения файла как ArrayBuffer */\n\t\t\treadMode: \"array-buffer\";\n\t });\n\n/**\n * InputFiles — компонент выбора нескольких файлов.\n *\n * Поле стилизовано как InputText. При клике открывается нативный\n * диалог с multiple. Каждый выбранный файл читается через readFile\n * и добавляется в массив value.\n *\n * Список выбранных файлов отображается под полем.\n * Каждый файл можно удалить кнопкой «крестик».\n *\n * InputFiles типизирует массив по `readMode`.\n * Если `readMode` не задан или равен `\"data-url\"`, в `value` и `onChange`\n * используется массив объектов с `dataUrl`. Если `readMode` равен\n * `\"array-buffer\"`, используется массив объектов с `buffer`.\n */\nexport function InputFiles(props: InputFilesProps) {\n\tconst {\n\t\tvalue,\n\t\tonReadError,\n\t\taccept,\n\t\tallowedMime,\n\t\tmaxBytes,\n\t\tmaxFiles,\n\t\tlabel,\n\t\tdescription,\n\t\tplaceholder = \"Выберите файлы\",\n\t\tdisabled,\n\t\tsize,\n\t\terror,\n\t\tonClearError,\n\t\tclassName\n\t} = props;\n\n\tassertValidAllowedMime(allowedMime);\n\tassertValidAccept(accept);\n\n\t/** Реф на скрытый нативный input[type=\"file\"] */\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\t/** Достигнут ли лимит файлов */\n\tconst isLimitReached = typeof maxFiles === \"number\" && value.length >= maxFiles;\n\n\t/**\n\t * Обработчик выбора файлов из нативного диалога.\n\t * Каждый файл читается через readFile.\n\t * Успешно прочитанные файлы добавляются к текущему массиву value.\n\t */\n\tconst handleChange = useCallback(\n\t\tasync (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tconst files = e.target.files;\n\t\t\tif (!files || files.length === 0) return;\n\n\t\t\tconst selectedFiles = Array.from(files);\n\n\t\t\t// Сбрасываем значение input чтобы можно было выбрать те же файлы повторно\n\t\t\te.target.value = \"\";\n\n\t\t\t// Сбрасываем ошибку при выборе новых файлов\n\t\t\tif (error && onClearError) onClearError();\n\n\t\t\t// Определяем сколько файлов можно ещё добавить\n\t\t\tconst remaining = typeof maxFiles === \"number\" ? maxFiles - value.length : selectedFiles.length;\n\t\t\tconst filesToProcess = selectedFiles.slice(0, remaining);\n\n\t\t\tif (props.readMode === \"array-buffer\") {\n\t\t\t\t// Читаем файлы как ArrayBuffer и сохраняем точный тип массива для потребителя.\n\t\t\t\tconst results: InputFilesArrayBufferResult[] = [];\n\n\t\t\t\tfor (const file of filesToProcess) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes, mode: \"array-buffer\" });\n\t\t\t\t\t\tresults.push(result);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tif (err instanceof ReadFileError && onReadError) {\n\t\t\t\t\t\t\tonReadError(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (results.length > 0) {\n\t\t\t\t\tprops.onChange([...props.value, ...results]);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Читаем файлы как Data URL и сохраняем точный тип массива для потребителя.\n\t\t\tconst results: InputFilesDataUrlResult[] = [];\n\t\t\tfor (const file of filesToProcess) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes });\n\t\t\t\t\tresults.push(result);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof ReadFileError && onReadError) {\n\t\t\t\t\t\tonReadError(err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (results.length > 0) {\n\t\t\t\tprops.onChange([...props.value, ...results]);\n\t\t\t}\n\t\t},\n\t\t[props, maxFiles, value.length, allowedMime, maxBytes, onReadError, error, onClearError]\n\t);\n\n\t/** Клик по видимому контролу открывает нативный диалог */\n\tconst handleClick = useCallback(() => {\n\t\tinputRef.current?.click();\n\t}, []);\n\n\tconst filesList =\n\t\tprops.readMode === \"array-buffer\" ? (\n\t\t\t<InputFilesList files={props.value} onChange={props.onChange} />\n\t\t) : (\n\t\t\t<InputFilesList files={props.value} onChange={props.onChange} />\n\t\t);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\tid={controlId}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={(accept ?? allowedMime)?.join(\",\")}\n\t\t\t\tmultiple\n\t\t\t\tdisabled={disabled || isLimitReached}\n\t\t\t\tclassName={styles.hiddenInput}\n\t\t\t\tonChange={handleChange}\n\t\t\t\ttabIndex={-1}\n\t\t\t/>\n\n\t\t\t<InputControl>\n\t\t\t\t{() => (\n\t\t\t\t\t<div\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\ttabIndex={disabled || isLimitReached ? -1 : 0}\n\t\t\t\t\t\tonClick={handleClick}\n\t\t\t\t\t\tonKeyDown={(event) => handleKeyboardActivation(event, handleClick, { disabled: disabled || isLimitReached })}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.control, !!error && \"invalid\")}\n\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\taria-invalid={!!error || undefined}\n\t\t\t\t\t\taria-disabled={disabled || isLimitReached}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}>\n\t\t\t\t\t\t<span className={uiStyles.uiPlaceholder}>{isLimitReached ? `Максимум ${maxFiles} файлов` : placeholder}</span>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\n\t\t\t{/* Список выбранных файлов */}\n\t\t\t{filesList}\n\t\t</InputUI>\n\t);\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./ui.module-BisoTevy.js";
|
|
2
|
-
import { c as t, n, o as r, r as i } from "./Input-
|
|
2
|
+
import { c as t, n, o as r, r as i } from "./Input-Wrew1puH.js";
|
|
3
3
|
import { cn as a, handleKeyboardActivation as o } from "@ryuzaki13/react-foundation-lib/utils";
|
|
4
4
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
5
|
import { useCallback as l, useMemo as u, useRef as d } from "react";
|
|
@@ -97,4 +97,4 @@ function h({ value: h, onChange: g, onClear: _, onReadError: v, allowedMime: y,
|
|
|
97
97
|
//#endregion
|
|
98
98
|
export { h as t };
|
|
99
99
|
|
|
100
|
-
//# sourceMappingURL=InputImage-
|
|
100
|
+
//# sourceMappingURL=InputImage-B522AQzl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputImage-
|
|
1
|
+
{"version":3,"file":"InputImage-B522AQzl.js","names":[],"sources":["../../src/input-image/InputImage.module.scss","../../src/input-image/InputImage.tsx"],"sourcesContent":[".control {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: 0 var(--space-sm);\n\tfont-size: var(--font-size-md);\n\tcursor: pointer;\n\tdisplay: flex;\n\talign-items: center;\n}\n\n.fileName {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.hiddenInput {\n\tposition: absolute;\n\twidth: 0;\n\theight: 0;\n\topacity: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n}\n","import { useCallback, useMemo, useRef } from \"react\";\n\nimport { ImageMime, ReadImageError, readImageFile, ReadImageResult, ReadMode } from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn, handleKeyboardActivation } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { InputClearButton, InputControl, InputUI, useInputFieldIds } from \"../input\";\nimport { UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./InputImage.module.scss\";\n\n/**\n * Пропсы компонента InputImage.\n *\n * Компонент предназначен для выбора одного изображения.\n * Внешний вид идентичен InputText.\n *\n * Под капотом использует readImageFile, который:\n * - Проверяет что файл является изображением (image/*)\n * - Валидирует MIME-тип по списку allowedMime\n * - В режиме \"data-url\" автоматически извлекает размеры изображения (dimensions)\n */\nexport interface InputImageProps extends UiBaseProps<ReadImageResult, ReadImageResult | undefined> {\n\t/** Callback очистки выбранного изображения. Если передан — отображается кнопка «крестик» */\n\tonClear?: () => void;\n\t/** Callback ошибки чтения (невалидный формат, не изображение, превышение размера и т.д.) */\n\tonReadError?: (error: ReadImageError) => void;\n\n\t/** Допустимые MIME-типы изображений — передаётся в readImageFile */\n\tallowedMime?: readonly ImageMime[];\n\t/** Максимальный размер файла в байтах — передаётся в readImageFile */\n\tmaxBytes?: number;\n\t/** Режим чтения: \"data-url\" (по умолчанию, с извлечением dimensions) или \"array-buffer\" */\n\treadMode?: ReadMode;\n\n\t/** Текст ошибки под полем */\n\terror?: string;\n\t/** Callback сброса ошибки (вызывается при повторном выборе изображения) */\n\tonClearError?: () => void;\n\t/** CSS-класс обёртки */\n\tclassName?: string;\n}\n\n/**\n * InputImage — компонент выбора одного изображения.\n *\n * Визуально идентичен InputText. Под капотом использует readImageFile,\n * который валидирует что файл — изображение и извлекает его размеры.\n *\n * HTML-атрибут accept формируется автоматически из allowedMime\n * или по умолчанию равен \"image/*\".\n */\nexport function InputImage({\n\tvalue,\n\tonChange,\n\tonClear,\n\tonReadError,\n\tallowedMime,\n\tmaxBytes,\n\treadMode,\n\tlabel,\n\tdescription,\n\tplaceholder = \"Выберите изображение\",\n\tdisabled,\n\tsize,\n\terror,\n\tonClearError,\n\tclassName\n}: InputImageProps) {\n\t/** Реф на скрытый нативный input[type=\"file\"] */\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\tconst readSelectedImage = useCallback(\n\t\t(file: File) => {\n\t\t\tif (readMode === \"array-buffer\") {\n\t\t\t\treturn readImageFile(file, { allowedMime, maxBytes, mode: \"array-buffer\" });\n\t\t\t}\n\n\t\t\treturn readImageFile(file, { allowedMime, maxBytes });\n\t\t},\n\t\t[allowedMime, maxBytes, readMode]\n\t);\n\n\t/**\n\t * Формируем HTML-атрибут accept из allowedMime.\n\t * Если allowedMime не указан — принимаем любые изображения (image/*).\n\t */\n\tconst accept = useMemo(() => {\n\t\tif (allowedMime && allowedMime.length > 0) {\n\t\t\treturn allowedMime.join(\",\");\n\t\t}\n\t\treturn \"image/*\";\n\t}, [allowedMime]);\n\n\t/**\n\t * Обработчик выбора файла из нативного диалога.\n\t * Читает файл через readImageFile и передаёт результат в onChange.\n\t */\n\tconst handleChange = useCallback(\n\t\tasync (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tconst file = e.target.files?.[0];\n\t\t\tif (!file) return;\n\n\t\t\t// Сбрасываем значение input чтобы можно было выбрать тот же файл повторно\n\t\t\te.target.value = \"\";\n\n\t\t\t// Сбрасываем ошибку при повторном выборе\n\t\t\tif (error && onClearError) onClearError();\n\n\t\t\ttry {\n\t\t\t\tconst result = await readSelectedImage(file);\n\t\t\t\tonChange(result);\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof ReadImageError && onReadError) {\n\t\t\t\t\tonReadError(err);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[readSelectedImage, onChange, onReadError, error, onClearError]\n\t);\n\n\t/** Клик по видимому контролу открывает нативный диалог */\n\tconst handleClick = useCallback(() => {\n\t\tinputRef.current?.click();\n\t}, []);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\tid={controlId}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={accept}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tclassName={styles.hiddenInput}\n\t\t\t\tonChange={handleChange}\n\t\t\t\ttabIndex={-1}\n\t\t\t/>\n\n\t\t\t{/* Видимый контрол, стилизованный под InputText */}\n\t\t\t<InputControl\n\t\t\t\tendAdornment={onClear ? <InputClearButton onClick={onClear} disabled={disabled} /> : undefined}\n\t\t\t\tendAdornmentWidth={onClear ? \"var(--control-height)\" : undefined}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\ttabIndex={disabled ? -1 : 0}\n\t\t\t\t\t\tonClick={handleClick}\n\t\t\t\t\t\tonKeyDown={(event) => handleKeyboardActivation(event, handleClick, { disabled })}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.control, controlClassName, !!error && \"invalid\")}\n\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\taria-invalid={!!error || undefined}\n\t\t\t\t\t\taria-disabled={disabled}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}>\n\t\t\t\t\t\t{value ? (\n\t\t\t\t\t\t\t<span className={styles.fileName}>{value.meta.name}</span>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span className={uiStyles.uiPlaceholder}>{placeholder}</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;ACoDA,SAAgB,EAAW,EAC1B,UACA,aACA,YACA,gBACA,gBACA,aACA,aACA,UACA,gBACA,iBAAc,wBACd,aACA,SACA,UACA,iBACA,gBACmB;CAEnB,IAAM,IAAW,EAAyB,IAAI,GACxC,EAAE,cAAW,YAAS,kBAAe,YAAS,mBAAgB,EAAiB;EACpF,UAAU,KAAiC;EAC3C,gBAAgB,CAAC,CAAC;EAClB,UAAU,CAAC,CAAC;CACb,CAAC,GAEK,IAAoB,GACxB,MACI,MAAa,iBACT,EAAc,GAAM;EAAE;EAAa;EAAU,MAAM;CAAe,CAAC,IAGpE,EAAc,GAAM;EAAE;EAAa;CAAS,CAAC,GAErD;EAAC;EAAa;EAAU;CAAQ,CACjC,GAMM,IAAS,QACV,KAAe,EAAY,SAAS,IAChC,EAAY,KAAK,GAAG,IAErB,WACL,CAAC,CAAW,CAAC,GAMV,IAAe,EACpB,OAAO,MAA2C;EACjD,IAAM,IAAO,EAAE,OAAO,QAAQ;EACzB,OAML;GAHA,EAAE,OAAO,QAAQ,IAGb,KAAS,KAAc,EAAa;GAExC,IAAI;IAEH,EAAS,MADY,EAAkB,CAAI,CAC5B;GAChB,SAAS,GAAK;IACb,AAAI,aAAe,KAAkB,KACpC,EAAY,CAAG;GAEjB;EATwC;CAUzC,GACA;EAAC;EAAmB;EAAU;EAAa;EAAO;CAAY,CAC/D,GAGM,IAAc,QAAkB;EACrC,EAAS,SAAS,MAAM;CACzB,GAAG,CAAC,CAAC;CAEL,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACC;EACL;EACC;EACI;EACF;EACM;EACN;YAVV,CAWC,kBAAC,SAAD;GACC,KAAK;GACL,IAAI;GACJ,MAAK;GACG;GACE;GACV,WAAW,EAAO;GAClB,UAAU;GACV,UAAU;EACV,CAAA,GAGD,kBAAC,GAAD;GACC,cAAc,IAAU,kBAAC,GAAD;IAAkB,SAAS;IAAmB;GAAW,CAAA,IAAI,KAAA;GACrF,mBAAmB,IAAU,0BAA0B,KAAA;cACrD,EAAE,0BACH,kBAAC,OAAD;IACC,MAAK;IACL,UAAU,IAAW,KAAK;IAC1B,SAAS;IACT,YAAY,MAAU,EAAyB,GAAO,GAAa,EAAE,YAAS,CAAC;IAC/E,WAAW,EAAG,EAAS,gBAAgB,EAAO,SAAS,GAAkB,CAAC,CAAC,KAAS,SAAS;IAC7F,iBAAe,KAAY,KAAA;IAC3B,gBAAc,CAAC,CAAC,KAAS,KAAA;IACzB,iBAAe;IACf,mBAAiB;IACjB,oBAAkB;cACjB,IACA,kBAAC,QAAD;KAAM,WAAW,EAAO;eAAW,EAAM,KAAK;IAAW,CAAA,IAEzD,kBAAC,QAAD;KAAM,WAAW,EAAS;eAAgB;IAAkB,CAAA;GAEzD,CAAA;EAEO,CAAA,CACN;;AAEX"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { l as e } from "./misc-
|
|
1
|
+
import { l as e } from "./misc-Bj0y3ERC.js";
|
|
2
2
|
import { t } from "./Button-BZ_b-Kin.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { cn as n } from "@ryuzaki13/react-foundation-lib/utils";
|
|
4
|
+
import { ChevronsLeftIcon as r, ChevronsRightIcon as i } from "lucide-react";
|
|
5
5
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
6
6
|
import { useCallback as s, useId as c, useState as l } from "react";
|
|
7
7
|
var u = {
|
|
@@ -22,9 +22,9 @@ function d({ children: d, className: f, contentClassName: p, toggleClassName: m,
|
|
|
22
22
|
O,
|
|
23
23
|
v,
|
|
24
24
|
k
|
|
25
|
-
]), j = () => A((e) => !e), M = k ?
|
|
25
|
+
]), j = () => A((e) => !e), M = k ? i : r;
|
|
26
26
|
return /* @__PURE__ */ o("div", {
|
|
27
|
-
className:
|
|
27
|
+
className: n(u.expandableActionPanel, f),
|
|
28
28
|
"data-ui": "expandable-action-panel",
|
|
29
29
|
"data-open": k ? "" : void 0,
|
|
30
30
|
children: [/* @__PURE__ */ a(t, {
|
|
@@ -42,7 +42,7 @@ function d({ children: d, className: f, contentClassName: p, toggleClassName: m,
|
|
|
42
42
|
id: D,
|
|
43
43
|
role: "group",
|
|
44
44
|
"aria-label": x,
|
|
45
|
-
className:
|
|
45
|
+
className: n(u.content, p),
|
|
46
46
|
children: /* @__PURE__ */ a(e, {
|
|
47
47
|
className: u.contentScroller,
|
|
48
48
|
itemSelector: S,
|
|
@@ -55,16 +55,16 @@ function d({ children: d, className: f, contentClassName: p, toggleClassName: m,
|
|
|
55
55
|
}
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region src/expandable-action-panel/LabeledExpandableActionPanel.tsx
|
|
58
|
-
function f({ label: e, className: t, labelClassName:
|
|
58
|
+
function f({ label: e, className: t, labelClassName: r, labelStyle: i, labelMinWidth: s = "12em", panelClassName: c, open: l, defaultOpen: f, ...p }) {
|
|
59
59
|
let m = {
|
|
60
|
-
...
|
|
60
|
+
...i,
|
|
61
61
|
minWidth: s
|
|
62
62
|
}, h = typeof e == "string" ? e : void 0;
|
|
63
63
|
return /* @__PURE__ */ o("div", {
|
|
64
|
-
className:
|
|
64
|
+
className: n(u.labeledPanel, t),
|
|
65
65
|
"data-ui": "labeled-expandable-action-panel",
|
|
66
66
|
children: [/* @__PURE__ */ a("div", {
|
|
67
|
-
className:
|
|
67
|
+
className: n("flexEllipsis", u.label, r),
|
|
68
68
|
style: m,
|
|
69
69
|
title: h,
|
|
70
70
|
children: e
|
|
@@ -72,11 +72,11 @@ function f({ label: e, className: t, labelClassName: n, labelStyle: r, labelMinW
|
|
|
72
72
|
...p,
|
|
73
73
|
open: l,
|
|
74
74
|
defaultOpen: f,
|
|
75
|
-
className:
|
|
75
|
+
className: n(u.labeledActionPanel, c)
|
|
76
76
|
})]
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
79
|
//#endregion
|
|
80
80
|
export { d as n, f as t };
|
|
81
81
|
|
|
82
|
-
//# sourceMappingURL=LabeledExpandableActionPanel-
|
|
82
|
+
//# sourceMappingURL=LabeledExpandableActionPanel-CWmOSWeS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LabeledExpandableActionPanel-CWmOSWeS.js","names":[],"sources":["../../src/expandable-action-panel/ExpandableActionPanel.module.scss","../../src/expandable-action-panel/ExpandableActionPanel.tsx","../../src/expandable-action-panel/LabeledExpandableActionPanel.tsx"],"sourcesContent":[".expandableActionPanel {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n\tgap: var(--space-sm);\n\tmin-width: var(--control-height);\n\tmax-width: 100%;\n\toverflow: hidden;\n}\n\n.content {\n\tmin-width: 0;\n\tmax-width: 100%;\n\tflex: 1 1 auto;\n\toverflow: hidden;\n}\n\n.contentScroller {\n\twidth: 100%;\n\tmin-width: 0;\n}\n\n.labeledPanel {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-sm);\n\twidth: 100%;\n\tmin-width: 0;\n}\n\n.label {\n\tcolor: var(--content-0);\n}\n\n.labeledActionPanel {\n\tflex: 0 1 auto;\n}\n","import React, { PropsWithChildren, useCallback, useId, useState } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { ChevronsLeftIcon, ChevronsRightIcon } from \"lucide-react\";\n\nimport { Button } from \"../button\";\nimport { OneStepScroller } from \"../misc\";\n\nimport styles from \"./ExpandableActionPanel.module.scss\";\n\nexport interface ExpandableActionPanelProps extends PropsWithChildren {\n\tclassName?: string;\n\tcontentClassName?: string;\n\ttoggleClassName?: string;\n\topen?: boolean;\n\tdefaultOpen?: boolean;\n\tdisabled?: boolean;\n\tonOpenChange?: (open: boolean) => void;\n\texpandLabel?: string;\n\tcollapseLabel?: string;\n\tpanelLabel?: string;\n\titemSelector?: string;\n\tscrollPadding?: number;\n\tsmoothScroll?: boolean;\n}\n\n/**\n * Горизонтальная раскрывающаяся панель действий.\n * Не знает о внешнем layout и может использоваться рядом с любым содержимым.\n */\nexport function ExpandableActionPanel({\n\tchildren,\n\tclassName,\n\tcontentClassName,\n\ttoggleClassName,\n\topen: controlledOpen,\n\tdefaultOpen = false,\n\tdisabled,\n\tonOpenChange,\n\texpandLabel = \"Раскрыть панель действий влево\",\n\tcollapseLabel = \"Свернуть панель действий\",\n\tpanelLabel = \"Действия панели\",\n\titemSelector,\n\tscrollPadding,\n\tsmoothScroll\n}: ExpandableActionPanelProps) {\n\tconst [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n\tconst panelId = useId();\n\tconst isControlled = controlledOpen !== undefined;\n\tconst open = isControlled ? controlledOpen : uncontrolledOpen;\n\n\tconst setOpen = useCallback<React.Dispatch<React.SetStateAction<boolean>>>(\n\t\t(value) => {\n\t\t\tconst nextOpen = typeof value === \"function\" ? value(open) : value;\n\n\t\t\tif (!isControlled) {\n\t\t\t\tsetUncontrolledOpen(nextOpen);\n\t\t\t}\n\n\t\t\tonOpenChange?.(nextOpen);\n\t\t},\n\t\t[isControlled, onOpenChange, open]\n\t);\n\n\tconst handleToggle = () => setOpen((prevOpen) => !prevOpen);\n\tconst ToggleIcon = open ? ChevronsRightIcon : ChevronsLeftIcon;\n\n\treturn (\n\t\t<div className={cn(styles.expandableActionPanel, className)} data-ui=\"expandable-action-panel\" data-open={open ? \"\" : undefined}>\n\t\t\t<Button\n\t\t\t\tclassName={toggleClassName}\n\t\t\t\ticon={<ToggleIcon />}\n\t\t\t\ttitle={open ? collapseLabel : expandLabel}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tvariant=\"neutralOutline\"\n\t\t\t\taria-expanded={open}\n\t\t\t\taria-controls={panelId}\n\t\t\t\tdata-ui=\"expandable-action-panel-toggle\"\n\t\t\t\tdata-action={open ? \"collapse-action-panel\" : \"expand-action-panel\"}\n\t\t\t\tonClick={handleToggle}\n\t\t\t/>\n\n\t\t\t{open && (\n\t\t\t\t<div id={panelId} role=\"group\" aria-label={panelLabel} className={cn(styles.content, contentClassName)}>\n\t\t\t\t\t<OneStepScroller\n\t\t\t\t\t\tclassName={styles.contentScroller}\n\t\t\t\t\t\titemSelector={itemSelector}\n\t\t\t\t\t\tscrollPadding={scrollPadding}\n\t\t\t\t\t\tsmooth={smoothScroll}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</OneStepScroller>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","import React from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { ExpandableActionPanel, ExpandableActionPanelProps } from \"./ExpandableActionPanel\";\nimport styles from \"./ExpandableActionPanel.module.scss\";\n\nexport interface LabeledExpandableActionPanelProps extends Omit<ExpandableActionPanelProps, \"className\"> {\n\tlabel: React.ReactNode;\n\tclassName?: string;\n\tlabelClassName?: string;\n\tlabelStyle?: React.CSSProperties;\n\tlabelMinWidth?: React.CSSProperties[\"minWidth\"];\n\tpanelClassName?: string;\n}\n\n/**\n * Раскрывающаяся панель действий с левым текстом, который сжимается через `flexEllipsis`.\n */\nexport function LabeledExpandableActionPanel({\n\tlabel,\n\tclassName,\n\tlabelClassName,\n\tlabelStyle,\n\tlabelMinWidth = \"12em\",\n\tpanelClassName,\n\topen,\n\tdefaultOpen,\n\t...panelProps\n}: LabeledExpandableActionPanelProps) {\n\tconst resolvedLabelStyle: React.CSSProperties = {\n\t\t...labelStyle,\n\t\tminWidth: labelMinWidth\n\t};\n\tconst title = typeof label === \"string\" ? label : undefined;\n\n\treturn (\n\t\t<div className={cn(styles.labeledPanel, className)} data-ui=\"labeled-expandable-action-panel\">\n\t\t\t<div className={cn(\"flexEllipsis\", styles.label, labelClassName)} style={resolvedLabelStyle} title={title}>\n\t\t\t\t{label}\n\t\t\t</div>\n\t\t\t<ExpandableActionPanel\n\t\t\t\t{...panelProps}\n\t\t\t\topen={open}\n\t\t\t\tdefaultOpen={defaultOpen}\n\t\t\t\tclassName={cn(styles.labeledActionPanel, panelClassName)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AC8BA,SAAgB,EAAsB,EACrC,aACA,cACA,qBACA,oBACA,MAAM,GACN,iBAAc,IACd,aACA,iBACA,iBAAc,kCACd,mBAAgB,4BAChB,gBAAa,mBACb,iBACA,kBACA,mBAC8B;CAC9B,IAAM,CAAC,GAAkB,KAAuB,EAAS,CAAW,GAC9D,IAAU,EAAM,GAChB,IAAe,MAAmB,KAAA,GAClC,IAAO,IAAe,IAAiB,GAEvC,IAAU,GACd,MAAU;EACV,IAAM,IAAW,OAAO,KAAU,aAAa,EAAM,CAAI,IAAI;EAM7D,AAJK,KACJ,EAAoB,CAAQ,GAG7B,IAAe,CAAQ;CACxB,GACA;EAAC;EAAc;EAAc;CAAI,CAClC,GAEM,UAAqB,GAAS,MAAa,CAAC,CAAQ,GACpD,IAAa,IAAO,IAAoB;CAE9C,OACC,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,uBAAuB,CAAS;EAAG,WAAQ;EAA0B,aAAW,IAAO,KAAK,KAAA;YAAtH,CACC,kBAAC,GAAD;GACC,WAAW;GACX,MAAM,kBAAC,GAAD,CAAa,CAAA;GACnB,OAAO,IAAO,IAAgB;GACpB;GACV,SAAQ;GACR,iBAAe;GACf,iBAAe;GACf,WAAQ;GACR,eAAa,IAAO,0BAA0B;GAC9C,SAAS;EACT,CAAA,GAEA,KACA,kBAAC,OAAD;GAAK,IAAI;GAAS,MAAK;GAAQ,cAAY;GAAY,WAAW,EAAG,EAAO,SAAS,CAAgB;aACpG,kBAAC,GAAD;IACC,WAAW,EAAO;IACJ;IACC;IACf,QAAQ;IACP;GACe,CAAA;EACb,CAAA,CAEF;;AAEP;;;AC5EA,SAAgB,EAA6B,EAC5C,UACA,cACA,mBACA,eACA,mBAAgB,QAChB,mBACA,SACA,gBACA,GAAG,KACkC;CACrC,IAAM,IAA0C;EAC/C,GAAG;EACH,UAAU;CACX,GACM,IAAQ,OAAO,KAAU,WAAW,IAAQ,KAAA;CAElD,OACC,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,cAAc,CAAS;EAAG,WAAQ;YAA5D,CACC,kBAAC,OAAD;GAAK,WAAW,EAAG,gBAAgB,EAAO,OAAO,CAAc;GAAG,OAAO;GAA2B;aAClG;EACG,CAAA,GACL,kBAAC,GAAD;GACC,GAAI;GACE;GACO;GACb,WAAW,EAAG,EAAO,oBAAoB,CAAc;EACvD,CAAA,CACG;;AAEP"}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { t as e } from "./ui.module-BisoTevy.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { cn as t, findFirstEnabledIndex as n, findLastEnabledIndex as r, findNextEnabledIndex as i, handleKeyboardActivation as a } from "@ryuzaki13/react-foundation-lib/utils";
|
|
3
|
+
import { CheckIcon as o } from "lucide-react";
|
|
4
4
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
5
|
import { useEffect as l, useId as u, useLayoutEffect as d, useMemo as f, useRef as p, useState as m } from "react";
|
|
6
6
|
//#region src/listbox/Listbox.tsx
|
|
7
7
|
var h = (e) => e.disabled === !0;
|
|
8
|
-
function g(e, t,
|
|
9
|
-
if (
|
|
8
|
+
function g(e, t, r) {
|
|
9
|
+
if (r) {
|
|
10
10
|
if (Array.isArray(t) && t.length > 0) {
|
|
11
11
|
let n = e.findIndex((e) => t.includes(e.value) && !e.disabled);
|
|
12
12
|
if (n >= 0) return n;
|
|
13
13
|
}
|
|
14
|
-
return
|
|
14
|
+
return n(e, h);
|
|
15
15
|
}
|
|
16
16
|
if (t !== void 0) {
|
|
17
17
|
let n = e.findIndex((e) => e.value === t && !e.disabled);
|
|
18
18
|
if (n >= 0) return n;
|
|
19
19
|
}
|
|
20
|
-
return
|
|
20
|
+
return n(e, h);
|
|
21
21
|
}
|
|
22
22
|
function _(_) {
|
|
23
23
|
let { value: v, defaultValue: y, multiple: b, focusOnMount: x, renderItem: S, getKey: C, options: w, onChange: T, id: E, ...D } = _, O = v !== void 0, k = u(), A = E ?? `${k}-listbox`, [j, M] = m(y), N = p(null), [P, F] = m(() => g(w, v ?? y, b)), I = f(() => (O ? v : j) ?? (b ? [] : null), [
|
|
@@ -47,35 +47,35 @@ function _(_) {
|
|
|
47
47
|
"aria-activedescendant": L >= 0 ? `${A}-option-${L}` : void 0,
|
|
48
48
|
tabIndex: 0,
|
|
49
49
|
onKeyDown: (e) => {
|
|
50
|
-
if (e.key === "ArrowDown") e.preventDefault(), F((e) =>
|
|
51
|
-
else if (e.key === "ArrowUp") e.preventDefault(), F((e) =>
|
|
52
|
-
else if (e.key === "Home") e.preventDefault(), F(
|
|
53
|
-
else if (e.key === "End") e.preventDefault(), F(
|
|
54
|
-
else if (
|
|
50
|
+
if (e.key === "ArrowDown") e.preventDefault(), F((e) => i(w, e, 1, h));
|
|
51
|
+
else if (e.key === "ArrowUp") e.preventDefault(), F((e) => i(w, e, -1, h));
|
|
52
|
+
else if (e.key === "Home") e.preventDefault(), F(n(w, h));
|
|
53
|
+
else if (e.key === "End") e.preventDefault(), F(r(w, h));
|
|
54
|
+
else if (a(e, () => {
|
|
55
55
|
let e = w[L];
|
|
56
56
|
e && R(e);
|
|
57
57
|
})) return;
|
|
58
58
|
},
|
|
59
59
|
...D,
|
|
60
|
-
className:
|
|
61
|
-
children: w.map((
|
|
62
|
-
let
|
|
60
|
+
className: t(e.uiPanel, "scrollable"),
|
|
61
|
+
children: w.map((n, r) => {
|
|
62
|
+
let i = b ? Array.isArray(I) && I.includes(n.value) : I === n.value, a = r === L;
|
|
63
63
|
return /* @__PURE__ */ c("li", {
|
|
64
|
-
id: `${A}-option-${
|
|
64
|
+
id: `${A}-option-${r}`,
|
|
65
65
|
role: "option",
|
|
66
|
-
"aria-selected":
|
|
67
|
-
"aria-disabled":
|
|
66
|
+
"aria-selected": i,
|
|
67
|
+
"aria-disabled": n.disabled || void 0,
|
|
68
68
|
onMouseDown: (e) => {
|
|
69
|
-
e.preventDefault(), !
|
|
69
|
+
e.preventDefault(), !n.disabled && (F(r), R(n));
|
|
70
70
|
},
|
|
71
71
|
tabIndex: -1,
|
|
72
|
-
className:
|
|
73
|
-
children: [s(
|
|
74
|
-
}, C ? C(
|
|
72
|
+
className: t(e.uiPopupOption, n.disabled && e.disabled, a && e.uiPopupOptionActive, i && e.selected),
|
|
73
|
+
children: [s(i ? o : "span", { className: e.uiPopupOptionIcon }), /* @__PURE__ */ s("div", { children: S ? S(n, i, a) : n.label ?? String(n.value) })]
|
|
74
|
+
}, C ? C(n, r) : r);
|
|
75
75
|
})
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
//#endregion
|
|
79
79
|
export { _ as t };
|
|
80
80
|
|
|
81
|
-
//# sourceMappingURL=Listbox-
|
|
81
|
+
//# sourceMappingURL=Listbox-B6F_IKQv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Listbox-B6F_IKQv.js","names":[],"sources":["../../src/listbox/Listbox.tsx"],"sourcesContent":["import { HTMLAttributes, JSX, KeyboardEvent, ReactNode, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from \"react\";\n\nimport {\n\tcn,\n\tfindFirstEnabledIndex,\n\tfindLastEnabledIndex,\n\tfindNextEnabledIndex,\n\thandleKeyboardActivation\n} from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { CheckIcon } from \"lucide-react\";\n\nimport uiStyles from \"../ui.module.scss\";\n\ntype ListboxOption<T> = {\n\tvalue: T;\n\tlabel?: string;\n\tdisabled?: boolean;\n};\n\ninterface ListboxBaseProps<T> extends Omit<HTMLAttributes<HTMLUListElement>, \"onChange\" | \"defaultValue\" | \"value\"> {\n\toptions: ListboxOption<T>[];\n\tfocusOnMount?: boolean;\n\trenderItem?: (option: ListboxOption<T>, selected: boolean, active: boolean) => ReactNode;\n\tgetKey?: (option: ListboxOption<T>, index: number) => string;\n}\n\n// Вариант для single-select\ninterface ListboxSingleProps<T> extends ListboxBaseProps<T> {\n\tmultiple?: false;\n\tvalue?: T;\n\tdefaultValue?: T;\n\tonChange?: (value: T, option: ListboxOption<T>) => void;\n}\n\n// Вариант для multi-select\ninterface ListboxMultiProps<T> extends ListboxBaseProps<T> {\n\tmultiple: true;\n\tvalue?: T[];\n\tdefaultValue?: T[];\n\tonChange?: (value: T[], option: ListboxOption<T>) => void;\n}\n\ntype ListboxProps<T> = ListboxSingleProps<T> | ListboxMultiProps<T>;\n\nconst isOptionDisabled = <T,>(option: ListboxOption<T>) => option.disabled === true;\n\nfunction getInitialFocusIndex<T>(options: ListboxOption<T>[], value: T | T[] | undefined, multiple: boolean | undefined) {\n\tif (multiple) {\n\t\tif (Array.isArray(value) && value.length > 0) {\n\t\t\tconst selectedIndex = options.findIndex((option) => value.includes(option.value) && !option.disabled);\n\t\t\tif (selectedIndex >= 0) {\n\t\t\t\treturn selectedIndex;\n\t\t\t}\n\t\t}\n\n\t\treturn findFirstEnabledIndex(options, isOptionDisabled);\n\t}\n\n\tif (value !== undefined) {\n\t\tconst selectedIndex = options.findIndex((option) => option.value === value && !option.disabled);\n\t\tif (selectedIndex >= 0) {\n\t\t\treturn selectedIndex;\n\t\t}\n\t}\n\n\treturn findFirstEnabledIndex(options, isOptionDisabled);\n}\n\n/**\n * Компонент выбора одного или нескольких элементов из списка. Поддерживает controlled API, поиск по данным и рендер кастомных опций.\n */\nexport function Listbox<T>(props: ListboxSingleProps<T>): JSX.Element;\nexport function Listbox<T>(props: ListboxMultiProps<T>): JSX.Element;\nexport function Listbox<T>(props: ListboxProps<T>): JSX.Element {\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\tconst { value, defaultValue, multiple, focusOnMount, renderItem, getKey, options, onChange, id: externalId, ...rest } = props;\n\n\tconst isControlled = value !== undefined;\n\tconst autoId = useId();\n\tconst listId = externalId ?? `${autoId}-listbox`;\n\tconst [internalValue, setInternalValue] = useState<T | T[] | undefined>(defaultValue);\n\tconst listRef = useRef<HTMLUListElement>(null);\n\tconst [focusedIndex, setFocusedIndex] = useState(() => getInitialFocusIndex(options, value ?? defaultValue, multiple));\n\t// const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);\n\n\tconst selectedValues = useMemo(\n\t\t() => (isControlled ? value : internalValue) ?? (multiple ? [] : null),\n\t\t[internalValue, isControlled, multiple, value]\n\t);\n\tconst activeIndex = /*hoveredIndex ??*/ focusedIndex;\n\n\tconst handleSelect = (option: ListboxOption<T>) => {\n\t\tif (option.disabled) return;\n\n\t\tlet newValue: T | T[];\n\t\tif (props.multiple) {\n\t\t\tconst arr = Array.isArray(selectedValues) ? selectedValues : [];\n\t\t\tnewValue = arr.includes(option.value) ? arr.filter((v) => v !== option.value) : [...arr, option.value];\n\n\t\t\tprops.onChange?.(newValue, option);\n\t\t} else {\n\t\t\tnewValue = option.value;\n\n\t\t\tprops.onChange?.(newValue, option);\n\t\t}\n\n\t\tif (!isControlled) setInternalValue(newValue);\n\t};\n\n\tconst handleKeyDown = (e: KeyboardEvent<HTMLUListElement>) => {\n\t\tif (e.key === \"ArrowDown\") {\n\t\t\te.preventDefault();\n\t\t\t// setHoveredIndex(null);\n\t\t\tsetFocusedIndex((index) => findNextEnabledIndex(options, index, 1, isOptionDisabled));\n\t\t} else if (e.key === \"ArrowUp\") {\n\t\t\te.preventDefault();\n\t\t\t// setHoveredIndex(null);\n\t\t\tsetFocusedIndex((index) => findNextEnabledIndex(options, index, -1, isOptionDisabled));\n\t\t} else if (e.key === \"Home\") {\n\t\t\te.preventDefault();\n\t\t\t// setHoveredIndex(null);\n\t\t\tsetFocusedIndex(findFirstEnabledIndex(options, isOptionDisabled));\n\t\t} else if (e.key === \"End\") {\n\t\t\te.preventDefault();\n\t\t\t// setHoveredIndex(null);\n\t\t\tsetFocusedIndex(findLastEnabledIndex(options, isOptionDisabled));\n\t\t} else if (\n\t\t\thandleKeyboardActivation(e, () => {\n\t\t\t\tconst activeOption = options[activeIndex];\n\t\t\t\tif (activeOption) {\n\t\t\t\t\thandleSelect(activeOption);\n\t\t\t\t}\n\t\t\t})\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t};\n\n\tuseEffect(() => {\n\t\tconst el = listRef.current?.querySelectorAll<HTMLElement>('[role=\"option\"]')[activeIndex];\n\t\tif (el) el.scrollIntoView({ block: \"nearest\" });\n\t}, [activeIndex]);\n\n\tuseLayoutEffect(() => {\n\t\tif (focusOnMount) {\n\t\t\tlistRef.current?.focus();\n\t\t}\n\t}, [focusOnMount]);\n\n\treturn (\n\t\t<ul\n\t\t\tref={listRef}\n\t\t\tid={listId}\n\t\t\trole=\"listbox\"\n\t\t\taria-multiselectable={multiple || undefined}\n\t\t\taria-activedescendant={activeIndex >= 0 ? `${listId}-option-${activeIndex}` : undefined}\n\t\t\ttabIndex={0}\n\t\t\t// onMouseLeave={() => setHoveredIndex(null)}\n\t\t\tonKeyDown={handleKeyDown}\n\t\t\t{...rest}\n\t\t\tclassName={cn(uiStyles.uiPanel, \"scrollable\")}>\n\t\t\t{options.map((option, index) => {\n\t\t\t\tconst selected = multiple\n\t\t\t\t\t? Array.isArray(selectedValues) && selectedValues.includes(option.value)\n\t\t\t\t\t: selectedValues === option.value;\n\t\t\t\tconst active = index === activeIndex;\n\n\t\t\t\treturn (\n\t\t\t\t\t<li\n\t\t\t\t\t\tkey={getKey ? getKey(option, index) : index}\n\t\t\t\t\t\tid={`${listId}-option-${index}`}\n\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\taria-selected={selected}\n\t\t\t\t\t\taria-disabled={option.disabled || undefined}\n\t\t\t\t\t\tonMouseDown={(e) => {\n\t\t\t\t\t\t\te.preventDefault(); // чтобы не сбрасывался фокус listbox\n\t\t\t\t\t\t\tif (option.disabled) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsetFocusedIndex(index);\n\t\t\t\t\t\t\t// setHoveredIndex(index);\n\t\t\t\t\t\t\thandleSelect(option);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\t// onMouseEnter={() => setHoveredIndex(index)}\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\tuiStyles.uiPopupOption,\n\t\t\t\t\t\t\toption.disabled && uiStyles.disabled,\n\t\t\t\t\t\t\tactive && uiStyles.uiPopupOptionActive,\n\t\t\t\t\t\t\tselected && uiStyles.selected\n\t\t\t\t\t\t)}>\n\t\t\t\t\t\t{selected ? (\n\t\t\t\t\t\t\t<CheckIcon className={uiStyles.uiPopupOptionIcon} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span className={uiStyles.uiPopupOptionIcon}></span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<div /*className={uiStyles.uiOptionText}*/>\n\t\t\t\t\t\t\t{renderItem ? renderItem(option, selected, active) : (option.label ?? String(option.value))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t);\n\t\t\t})}\n\t\t</ul>\n\t);\n}\n"],"mappings":"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"}
|