huibo-ui 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/{a11y-802de67a.js → a11y-4385c871.js} +17 -2
- package/dist/cjs/a11y-4385c871.js.map +1 -0
- package/dist/cjs/{date-helpers-1ffddc59.js → date-helpers-c05ef385.js} +5 -16
- package/dist/cjs/date-helpers-c05ef385.js.map +1 -0
- package/dist/cjs/hb-alert.cjs.entry.js +2 -1
- package/dist/cjs/hb-alert.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-calendar.cjs.entry.js +2 -2
- package/dist/cjs/hb-calendar.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-cascader.cjs.entry.js +48 -12
- package/dist/cjs/hb-cascader.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-checkbox-group.cjs.entry.js +12 -8
- package/dist/cjs/hb-checkbox-group.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-checkbox.cjs.entry.js +9 -4
- package/dist/cjs/hb-checkbox.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-collapse-item.cjs.entry.js +13 -4
- package/dist/cjs/hb-collapse-item.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-collapse.cjs.entry.js +20 -15
- package/dist/cjs/hb-collapse.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-color-picker.cjs.entry.js +22 -19
- package/dist/cjs/hb-color-picker.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-date-picker-pane.cjs.entry.js +1 -1
- package/dist/cjs/hb-date-picker.cjs.entry.js +13 -10
- package/dist/cjs/hb-date-picker.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-date-range-picker.cjs.entry.js +1 -1
- package/dist/cjs/hb-date-time-picker.cjs.entry.js +1 -1
- package/dist/cjs/hb-descriptions.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-dialog.cjs.entry.js +51 -12
- package/dist/cjs/hb-dialog.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-drawer.cjs.entry.js +34 -4
- package/dist/cjs/hb-drawer.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-dropdown.cjs.entry.js +27 -15
- package/dist/cjs/hb-dropdown.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-empty.cjs.entry.js +1 -1
- package/dist/cjs/hb-float-button.cjs.entry.js +2 -2
- package/dist/cjs/hb-form-item.cjs.entry.js +67 -16
- package/dist/cjs/hb-form-item.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-form.cjs.entry.js +115 -7
- package/dist/cjs/hb-form.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-image-preview.cjs.entry.js +1 -1
- package/dist/cjs/hb-image-preview.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-image.cjs.entry.js +21 -3
- package/dist/cjs/hb-image.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-input-number.cjs.entry.js +7 -7
- package/dist/cjs/hb-input-number.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-input-tag.cjs.entry.js +2 -2
- package/dist/cjs/hb-input.cjs.entry.js +3 -2
- package/dist/cjs/hb-input.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-layout.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-link.cjs.entry.js +2 -2
- package/dist/cjs/hb-loading.cjs.entry.js +2 -2
- package/dist/cjs/hb-menu-item.cjs.entry.js +14 -5
- package/dist/cjs/hb-menu-item.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-menu.cjs.entry.js +2 -2
- package/dist/cjs/hb-message.cjs.entry.js +13 -4
- package/dist/cjs/hb-message.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-page-header.cjs.entry.js +1 -1
- package/dist/cjs/hb-pagination.cjs.entry.js +8 -5
- package/dist/cjs/hb-pagination.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-popconfirm.cjs.entry.js +27 -8
- package/dist/cjs/hb-popconfirm.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-popover.cjs.entry.js +26 -14
- package/dist/cjs/hb-popover.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-progress.cjs.entry.js +1 -1
- package/dist/cjs/hb-radio.cjs.entry.js +8 -3
- package/dist/cjs/hb-radio.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-rate.cjs.entry.js +3 -3
- package/dist/cjs/hb-rate.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-row.cjs.entry.js +2 -2
- package/dist/cjs/hb-scrollbar.cjs.entry.js +5 -5
- package/dist/cjs/hb-scrollbar.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-segmented.cjs.entry.js +13 -2
- package/dist/cjs/hb-segmented.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-select.cjs.entry.js +100 -19
- package/dist/cjs/hb-select.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-slider.cjs.entry.js +6 -12
- package/dist/cjs/hb-slider.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-space.cjs.entry.js +2 -2
- package/dist/cjs/hb-statistic.cjs.entry.js +1 -1
- package/dist/cjs/hb-step.cjs.entry.js +1 -1
- package/dist/cjs/hb-steps.cjs.entry.js +3 -3
- package/dist/cjs/hb-steps.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-sub-menu.cjs.entry.js +5 -5
- package/dist/cjs/hb-switch.cjs.entry.js +3 -3
- package/dist/cjs/hb-switch.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-tab-pane.cjs.entry.js +1 -1
- package/dist/cjs/hb-table.cjs.entry.js +218 -41
- package/dist/cjs/hb-table.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-tabs.cjs.entry.js +31 -10
- package/dist/cjs/hb-tabs.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-tag.cjs.entry.js +3 -2
- package/dist/cjs/hb-tag.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-text.cjs.entry.js +2 -2
- package/dist/cjs/hb-time-picker.cjs.entry.js +14 -9
- package/dist/cjs/hb-time-picker.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-time-select.cjs.entry.js +13 -4
- package/dist/cjs/hb-time-select.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-tooltip.cjs.entry.js +30 -10
- package/dist/cjs/hb-tooltip.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-tree-select.cjs.entry.js +125 -10
- package/dist/cjs/hb-tree-select.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-tree.cjs.entry.js +145 -12
- package/dist/cjs/hb-tree.cjs.entry.js.map +1 -1
- package/dist/cjs/hb-watermark.cjs.entry.js +19 -11
- package/dist/cjs/hb-watermark.cjs.entry.js.map +1 -1
- package/dist/cjs/huibo-ui.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/transition-59f1da0f.js +34 -0
- package/dist/cjs/transition-59f1da0f.js.map +1 -0
- package/dist/collection/components/Alert/Alert.js +2 -1
- package/dist/collection/components/Alert/Alert.js.map +1 -1
- package/dist/collection/components/Calendar/Calendar.js +2 -2
- package/dist/collection/components/Calendar/Calendar.js.map +1 -1
- package/dist/collection/components/Cascader/Cascader.js +47 -11
- package/dist/collection/components/Cascader/Cascader.js.map +1 -1
- package/dist/collection/components/Checkbox/Checkbox.js +9 -4
- package/dist/collection/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/collection/components/Checkbox/CheckboxGroup.js +12 -8
- package/dist/collection/components/Checkbox/CheckboxGroup.js.map +1 -1
- package/dist/collection/components/Collapse/Collapse.js +20 -15
- package/dist/collection/components/Collapse/Collapse.js.map +1 -1
- package/dist/collection/components/Collapse/CollapseItem.js +33 -4
- package/dist/collection/components/Collapse/CollapseItem.js.map +1 -1
- package/dist/collection/components/ColorPicker/ColorPicker.js +22 -19
- package/dist/collection/components/ColorPicker/ColorPicker.js.map +1 -1
- package/dist/collection/components/ColorPicker/color-picker.css +8 -3
- package/dist/collection/components/DatePicker/DatePicker.js +12 -9
- package/dist/collection/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/collection/components/DatePicker/date-picker.css +3 -2
- package/dist/collection/components/Descriptions/descriptions.css +30 -10
- package/dist/collection/components/Dialog/Dialog.js +54 -10
- package/dist/collection/components/Dialog/Dialog.js.map +1 -1
- package/dist/collection/components/Dialog/dialog.css +57 -11
- package/dist/collection/components/Drawer/Drawer.js +34 -3
- package/dist/collection/components/Drawer/Drawer.js.map +1 -1
- package/dist/collection/components/Drawer/drawer.css +207 -17
- package/dist/collection/components/Dropdown/Dropdown.js +28 -13
- package/dist/collection/components/Dropdown/Dropdown.js.map +1 -1
- package/dist/collection/components/Dropdown/dropdown.css +24 -2
- package/dist/collection/components/Empty/Empty.js +1 -1
- package/dist/collection/components/FloatButton/FloatButton.js +2 -2
- package/dist/collection/components/Form/Form.js +217 -9
- package/dist/collection/components/Form/Form.js.map +1 -1
- package/dist/collection/components/Form/FormItem.js +126 -18
- package/dist/collection/components/Form/FormItem.js.map +1 -1
- package/dist/collection/components/Form/form-item.css +8 -2
- package/dist/collection/components/Image/Image.js +24 -3
- package/dist/collection/components/Image/Image.js.map +1 -1
- package/dist/collection/components/ImagePreview/ImagePreview.js +1 -1
- package/dist/collection/components/ImagePreview/ImagePreview.js.map +1 -1
- package/dist/collection/components/Input/Input.js +3 -2
- package/dist/collection/components/Input/Input.js.map +1 -1
- package/dist/collection/components/Input/input.css +1 -2
- package/dist/collection/components/InputNumber/InputNumber.js +6 -6
- package/dist/collection/components/InputNumber/InputNumber.js.map +1 -1
- package/dist/collection/components/InputNumber/input-number.css +11 -1
- package/dist/collection/components/InputTag/InputTag.js +2 -2
- package/dist/collection/components/Layout/Layout.js.map +1 -1
- package/dist/collection/components/Layout/Row.js +2 -2
- package/dist/collection/components/Layout/layout.css +1713 -576
- package/dist/collection/components/Link/Link.js +2 -2
- package/dist/collection/components/Loading/Loading.js +2 -2
- package/dist/collection/components/Menu/Menu.js +2 -2
- package/dist/collection/components/Menu/MenuItem.js +34 -5
- package/dist/collection/components/Menu/MenuItem.js.map +1 -1
- package/dist/collection/components/Menu/SubMenu.js +4 -4
- package/dist/collection/components/Message/Message.js +13 -4
- package/dist/collection/components/Message/Message.js.map +1 -1
- package/dist/collection/components/PageHeader/PageHeader.js +1 -1
- package/dist/collection/components/Pagination/Pagination.js +8 -5
- package/dist/collection/components/Pagination/Pagination.js.map +1 -1
- package/dist/collection/components/Popconfirm/Popconfirm.js +28 -6
- package/dist/collection/components/Popconfirm/Popconfirm.js.map +1 -1
- package/dist/collection/components/Popconfirm/popconfirm.css +80 -16
- package/dist/collection/components/Popover/Popover.js +27 -12
- package/dist/collection/components/Popover/Popover.js.map +1 -1
- package/dist/collection/components/Popover/popover.css +49 -8
- package/dist/collection/components/Progress/Progress.js +1 -1
- package/dist/collection/components/Radio/Radio.js +8 -3
- package/dist/collection/components/Radio/Radio.js.map +1 -1
- package/dist/collection/components/Rate/Rate.js +3 -3
- package/dist/collection/components/Rate/Rate.js.map +1 -1
- package/dist/collection/components/Scrollbar/Scrollbar.js +5 -5
- package/dist/collection/components/Scrollbar/Scrollbar.js.map +1 -1
- package/dist/collection/components/Segmented/Segmented.js +15 -1
- package/dist/collection/components/Segmented/Segmented.js.map +1 -1
- package/dist/collection/components/Select/Select.js +123 -19
- package/dist/collection/components/Select/Select.js.map +1 -1
- package/dist/collection/components/Select/select.css +0 -1
- package/dist/collection/components/Slider/Slider.js +6 -12
- package/dist/collection/components/Slider/Slider.js.map +1 -1
- package/dist/collection/components/Slider/slider.css +0 -1
- package/dist/collection/components/Space/Space.js +2 -2
- package/dist/collection/components/Statistic/Statistic.js +1 -1
- package/dist/collection/components/Steps/Step.js +1 -1
- package/dist/collection/components/Steps/Steps.js +2 -2
- package/dist/collection/components/Steps/Steps.js.map +1 -1
- package/dist/collection/components/Switch/Switch.js +3 -3
- package/dist/collection/components/Switch/Switch.js.map +1 -1
- package/dist/collection/components/Switch/switch.css +3 -2
- package/dist/collection/components/Table/Table.js +296 -41
- package/dist/collection/components/Table/Table.js.map +1 -1
- package/dist/collection/components/Table/table.css +6 -2
- package/dist/collection/components/Tabs/TabPane.js +1 -1
- package/dist/collection/components/Tabs/Tabs.js +31 -10
- package/dist/collection/components/Tabs/Tabs.js.map +1 -1
- package/dist/collection/components/Tag/Tag.js +3 -2
- package/dist/collection/components/Tag/Tag.js.map +1 -1
- package/dist/collection/components/Text/Text.js +2 -2
- package/dist/collection/components/TimePicker/TimePicker.js +14 -9
- package/dist/collection/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/collection/components/TimeSelect/TimeSelect.js +13 -4
- package/dist/collection/components/TimeSelect/TimeSelect.js.map +1 -1
- package/dist/collection/components/Tooltip/Tooltip.js +31 -8
- package/dist/collection/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/collection/components/Tooltip/tooltip.css +24 -2
- package/dist/collection/components/Tree/Tree.js +147 -13
- package/dist/collection/components/Tree/Tree.js.map +1 -1
- package/dist/collection/components/TreeSelect/TreeSelect.js +130 -11
- package/dist/collection/components/TreeSelect/TreeSelect.js.map +1 -1
- package/dist/collection/components/Watermark/Watermark.js +19 -11
- package/dist/collection/components/Watermark/Watermark.js.map +1 -1
- package/dist/collection/utils/a11y.js +15 -1
- package/dist/collection/utils/a11y.js.map +1 -1
- package/dist/collection/utils/date-helpers.js +4 -15
- package/dist/collection/utils/date-helpers.js.map +1 -1
- package/dist/collection/utils/transition.js +29 -0
- package/dist/collection/utils/transition.js.map +1 -0
- package/dist/collection/utils/virtual-scroll.js +39 -0
- package/dist/collection/utils/virtual-scroll.js.map +1 -0
- package/dist/components/hb-alert.js +2 -1
- package/dist/components/hb-alert.js.map +1 -1
- package/dist/components/hb-calendar.js +2 -2
- package/dist/components/hb-calendar.js.map +1 -1
- package/dist/components/hb-cascader.js +48 -12
- package/dist/components/hb-cascader.js.map +1 -1
- package/dist/components/hb-checkbox-group.js +12 -8
- package/dist/components/hb-checkbox-group.js.map +1 -1
- package/dist/components/hb-checkbox.js +9 -4
- package/dist/components/hb-checkbox.js.map +1 -1
- package/dist/components/hb-collapse-item.js +14 -4
- package/dist/components/hb-collapse-item.js.map +1 -1
- package/dist/components/hb-collapse.js +20 -15
- package/dist/components/hb-collapse.js.map +1 -1
- package/dist/components/hb-color-picker.js +22 -19
- package/dist/components/hb-color-picker.js.map +1 -1
- package/dist/components/hb-date-picker-pane.js +1 -1
- package/dist/components/hb-date-picker.js +13 -10
- package/dist/components/hb-date-picker.js.map +1 -1
- package/dist/components/hb-date-range-picker.js +1 -1
- package/dist/components/hb-date-time-picker.js +1 -1
- package/dist/components/hb-descriptions.js.map +1 -1
- package/dist/components/hb-dialog.js +53 -13
- package/dist/components/hb-dialog.js.map +1 -1
- package/dist/components/hb-drawer.js +36 -5
- package/dist/components/hb-drawer.js.map +1 -1
- package/dist/components/hb-dropdown.js +28 -15
- package/dist/components/hb-dropdown.js.map +1 -1
- package/dist/components/hb-empty.js +1 -1
- package/dist/components/hb-float-button.js +2 -2
- package/dist/components/hb-form-item.js +70 -16
- package/dist/components/hb-form-item.js.map +1 -1
- package/dist/components/hb-form.js +120 -7
- package/dist/components/hb-form.js.map +1 -1
- package/dist/components/hb-image-preview.js +1 -1
- package/dist/components/hb-image-preview.js.map +1 -1
- package/dist/components/hb-image.js +23 -3
- package/dist/components/hb-image.js.map +1 -1
- package/dist/components/hb-input-number.js +7 -7
- package/dist/components/hb-input-number.js.map +1 -1
- package/dist/components/hb-input-tag.js +2 -2
- package/dist/components/hb-input.js +3 -2
- package/dist/components/hb-input.js.map +1 -1
- package/dist/components/hb-layout.js.map +1 -1
- package/dist/components/hb-link.js +2 -2
- package/dist/components/hb-loading.js +2 -2
- package/dist/components/hb-menu-item.js +15 -5
- package/dist/components/hb-menu-item.js.map +1 -1
- package/dist/components/hb-menu.js +2 -2
- package/dist/components/hb-message.js +13 -4
- package/dist/components/hb-message.js.map +1 -1
- package/dist/components/hb-page-header.js +1 -1
- package/dist/components/hb-pagination.js +8 -5
- package/dist/components/hb-pagination.js.map +1 -1
- package/dist/components/hb-popconfirm.js +28 -8
- package/dist/components/hb-popconfirm.js.map +1 -1
- package/dist/components/hb-popover.js +27 -14
- package/dist/components/hb-popover.js.map +1 -1
- package/dist/components/hb-progress.js +1 -1
- package/dist/components/hb-radio.js +8 -3
- package/dist/components/hb-radio.js.map +1 -1
- package/dist/components/hb-rate.js +3 -3
- package/dist/components/hb-rate.js.map +1 -1
- package/dist/components/hb-row.js +2 -2
- package/dist/components/hb-scrollbar.js +5 -5
- package/dist/components/hb-scrollbar.js.map +1 -1
- package/dist/components/hb-segmented.js +15 -2
- package/dist/components/hb-segmented.js.map +1 -1
- package/dist/components/hb-select.js +105 -20
- package/dist/components/hb-select.js.map +1 -1
- package/dist/components/hb-slider.js +6 -12
- package/dist/components/hb-slider.js.map +1 -1
- package/dist/components/hb-space.js +2 -2
- package/dist/components/hb-statistic.js +1 -1
- package/dist/components/hb-step.js +1 -1
- package/dist/components/hb-steps.js +3 -3
- package/dist/components/hb-steps.js.map +1 -1
- package/dist/components/hb-sub-menu.js +5 -5
- package/dist/components/hb-switch.js +3 -3
- package/dist/components/hb-switch.js.map +1 -1
- package/dist/components/hb-tab-pane.js +1 -1
- package/dist/components/hb-table.js +226 -43
- package/dist/components/hb-table.js.map +1 -1
- package/dist/components/hb-tabs.js +31 -10
- package/dist/components/hb-tabs.js.map +1 -1
- package/dist/components/hb-tag.js +3 -2
- package/dist/components/hb-tag.js.map +1 -1
- package/dist/components/hb-text.js +2 -2
- package/dist/components/hb-time-picker.js +14 -9
- package/dist/components/hb-time-picker.js.map +1 -1
- package/dist/components/hb-time-select.js +13 -4
- package/dist/components/hb-time-select.js.map +1 -1
- package/dist/components/hb-tooltip.js +31 -10
- package/dist/components/hb-tooltip.js.map +1 -1
- package/dist/components/hb-tree-select.js +129 -11
- package/dist/components/hb-tree-select.js.map +1 -1
- package/dist/components/hb-tree.js +147 -13
- package/dist/components/hb-tree.js.map +1 -1
- package/dist/components/hb-watermark.js +19 -11
- package/dist/components/hb-watermark.js.map +1 -1
- package/dist/{esm/a11y-f9ab2964.js → components/p-00aa34c8.js} +17 -3
- package/dist/components/p-00aa34c8.js.map +1 -0
- package/dist/components/{p-08b4005c.js → p-e0876aca.js} +5 -16
- package/dist/components/p-e0876aca.js.map +1 -0
- package/dist/components/p-fad66d69.js +32 -0
- package/dist/components/p-fad66d69.js.map +1 -0
- package/dist/{components/p-cc0aeb50.js → esm/a11y-e4cde5b0.js} +17 -3
- package/dist/esm/a11y-e4cde5b0.js.map +1 -0
- package/dist/esm/{date-helpers-44507189.js → date-helpers-259ed2f1.js} +5 -16
- package/dist/esm/date-helpers-259ed2f1.js.map +1 -0
- package/dist/esm/hb-alert.entry.js +2 -1
- package/dist/esm/hb-alert.entry.js.map +1 -1
- package/dist/esm/hb-calendar.entry.js +2 -2
- package/dist/esm/hb-calendar.entry.js.map +1 -1
- package/dist/esm/hb-cascader.entry.js +48 -12
- package/dist/esm/hb-cascader.entry.js.map +1 -1
- package/dist/esm/hb-checkbox-group.entry.js +12 -8
- package/dist/esm/hb-checkbox-group.entry.js.map +1 -1
- package/dist/esm/hb-checkbox.entry.js +9 -4
- package/dist/esm/hb-checkbox.entry.js.map +1 -1
- package/dist/esm/hb-collapse-item.entry.js +13 -4
- package/dist/esm/hb-collapse-item.entry.js.map +1 -1
- package/dist/esm/hb-collapse.entry.js +20 -15
- package/dist/esm/hb-collapse.entry.js.map +1 -1
- package/dist/esm/hb-color-picker.entry.js +22 -19
- package/dist/esm/hb-color-picker.entry.js.map +1 -1
- package/dist/esm/hb-date-picker-pane.entry.js +1 -1
- package/dist/esm/hb-date-picker.entry.js +13 -10
- package/dist/esm/hb-date-picker.entry.js.map +1 -1
- package/dist/esm/hb-date-range-picker.entry.js +1 -1
- package/dist/esm/hb-date-time-picker.entry.js +1 -1
- package/dist/esm/hb-descriptions.entry.js.map +1 -1
- package/dist/esm/hb-dialog.entry.js +51 -12
- package/dist/esm/hb-dialog.entry.js.map +1 -1
- package/dist/esm/hb-drawer.entry.js +34 -4
- package/dist/esm/hb-drawer.entry.js.map +1 -1
- package/dist/esm/hb-dropdown.entry.js +27 -15
- package/dist/esm/hb-dropdown.entry.js.map +1 -1
- package/dist/esm/hb-empty.entry.js +1 -1
- package/dist/esm/hb-float-button.entry.js +2 -2
- package/dist/esm/hb-form-item.entry.js +67 -16
- package/dist/esm/hb-form-item.entry.js.map +1 -1
- package/dist/esm/hb-form.entry.js +115 -7
- package/dist/esm/hb-form.entry.js.map +1 -1
- package/dist/esm/hb-image-preview.entry.js +1 -1
- package/dist/esm/hb-image-preview.entry.js.map +1 -1
- package/dist/esm/hb-image.entry.js +21 -3
- package/dist/esm/hb-image.entry.js.map +1 -1
- package/dist/esm/hb-input-number.entry.js +7 -7
- package/dist/esm/hb-input-number.entry.js.map +1 -1
- package/dist/esm/hb-input-tag.entry.js +2 -2
- package/dist/esm/hb-input.entry.js +3 -2
- package/dist/esm/hb-input.entry.js.map +1 -1
- package/dist/esm/hb-layout.entry.js.map +1 -1
- package/dist/esm/hb-link.entry.js +2 -2
- package/dist/esm/hb-loading.entry.js +2 -2
- package/dist/esm/hb-menu-item.entry.js +14 -5
- package/dist/esm/hb-menu-item.entry.js.map +1 -1
- package/dist/esm/hb-menu.entry.js +2 -2
- package/dist/esm/hb-message.entry.js +13 -4
- package/dist/esm/hb-message.entry.js.map +1 -1
- package/dist/esm/hb-page-header.entry.js +1 -1
- package/dist/esm/hb-pagination.entry.js +8 -5
- package/dist/esm/hb-pagination.entry.js.map +1 -1
- package/dist/esm/hb-popconfirm.entry.js +27 -8
- package/dist/esm/hb-popconfirm.entry.js.map +1 -1
- package/dist/esm/hb-popover.entry.js +26 -14
- package/dist/esm/hb-popover.entry.js.map +1 -1
- package/dist/esm/hb-progress.entry.js +1 -1
- package/dist/esm/hb-radio.entry.js +8 -3
- package/dist/esm/hb-radio.entry.js.map +1 -1
- package/dist/esm/hb-rate.entry.js +3 -3
- package/dist/esm/hb-rate.entry.js.map +1 -1
- package/dist/esm/hb-row.entry.js +2 -2
- package/dist/esm/hb-scrollbar.entry.js +5 -5
- package/dist/esm/hb-scrollbar.entry.js.map +1 -1
- package/dist/esm/hb-segmented.entry.js +13 -2
- package/dist/esm/hb-segmented.entry.js.map +1 -1
- package/dist/esm/hb-select.entry.js +100 -19
- package/dist/esm/hb-select.entry.js.map +1 -1
- package/dist/esm/hb-slider.entry.js +6 -12
- package/dist/esm/hb-slider.entry.js.map +1 -1
- package/dist/esm/hb-space.entry.js +2 -2
- package/dist/esm/hb-statistic.entry.js +1 -1
- package/dist/esm/hb-step.entry.js +1 -1
- package/dist/esm/hb-steps.entry.js +3 -3
- package/dist/esm/hb-steps.entry.js.map +1 -1
- package/dist/esm/hb-sub-menu.entry.js +5 -5
- package/dist/esm/hb-switch.entry.js +3 -3
- package/dist/esm/hb-switch.entry.js.map +1 -1
- package/dist/esm/hb-tab-pane.entry.js +1 -1
- package/dist/esm/hb-table.entry.js +218 -41
- package/dist/esm/hb-table.entry.js.map +1 -1
- package/dist/esm/hb-tabs.entry.js +31 -10
- package/dist/esm/hb-tabs.entry.js.map +1 -1
- package/dist/esm/hb-tag.entry.js +3 -2
- package/dist/esm/hb-tag.entry.js.map +1 -1
- package/dist/esm/hb-text.entry.js +2 -2
- package/dist/esm/hb-time-picker.entry.js +14 -9
- package/dist/esm/hb-time-picker.entry.js.map +1 -1
- package/dist/esm/hb-time-select.entry.js +13 -4
- package/dist/esm/hb-time-select.entry.js.map +1 -1
- package/dist/esm/hb-tooltip.entry.js +30 -10
- package/dist/esm/hb-tooltip.entry.js.map +1 -1
- package/dist/esm/hb-tree-select.entry.js +125 -10
- package/dist/esm/hb-tree-select.entry.js.map +1 -1
- package/dist/esm/hb-tree.entry.js +145 -12
- package/dist/esm/hb-tree.entry.js.map +1 -1
- package/dist/esm/hb-watermark.entry.js +19 -11
- package/dist/esm/hb-watermark.entry.js.map +1 -1
- package/dist/esm/huibo-ui.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/transition-4295d789.js +32 -0
- package/dist/esm/transition-4295d789.js.map +1 -0
- package/dist/huibo-ui/huibo-ui.esm.js +1 -1
- package/dist/huibo-ui/huibo-ui.esm.js.map +1 -1
- package/dist/huibo-ui/p-00aa34c8.js +2 -0
- package/dist/huibo-ui/p-00aa34c8.js.map +1 -0
- package/dist/huibo-ui/p-0cc1e3f3.entry.js +2 -0
- package/dist/huibo-ui/p-0cc1e3f3.entry.js.map +1 -0
- package/dist/huibo-ui/{p-678b4212.entry.js → p-0ddae4e9.entry.js} +2 -2
- package/dist/huibo-ui/p-10f6c184.entry.js.map +1 -1
- package/dist/huibo-ui/{p-f4336be9.entry.js → p-14c3b47b.entry.js} +2 -2
- package/dist/huibo-ui/{p-c50ad398.entry.js → p-193efdc0.entry.js} +2 -2
- package/dist/huibo-ui/{p-735bceef.entry.js → p-1b98152b.entry.js} +2 -2
- package/dist/huibo-ui/p-1b98152b.entry.js.map +1 -0
- package/dist/huibo-ui/p-1f6d0adb.entry.js +2 -0
- package/dist/huibo-ui/p-1f6d0adb.entry.js.map +1 -0
- package/dist/huibo-ui/{p-0d4b2997.entry.js → p-2bcda1bb.entry.js} +2 -2
- package/dist/huibo-ui/{p-b8d87f7e.entry.js → p-2ca9796a.entry.js} +2 -2
- package/dist/huibo-ui/p-2ca9796a.entry.js.map +1 -0
- package/dist/huibo-ui/{p-c80f8ace.entry.js → p-2cf5bf20.entry.js} +2 -2
- package/dist/huibo-ui/p-2cf5bf20.entry.js.map +1 -0
- package/dist/huibo-ui/{p-7da14d7c.entry.js → p-3042f986.entry.js} +2 -2
- package/dist/huibo-ui/{p-e039155d.entry.js → p-3dacb26b.entry.js} +2 -2
- package/dist/huibo-ui/{p-a084b8e5.entry.js → p-412ff618.entry.js} +2 -2
- package/dist/huibo-ui/p-4148d875.entry.js +2 -0
- package/dist/huibo-ui/p-4148d875.entry.js.map +1 -0
- package/dist/huibo-ui/{p-6beb5b81.entry.js → p-415295f3.entry.js} +2 -2
- package/dist/huibo-ui/p-415295f3.entry.js.map +1 -0
- package/dist/huibo-ui/p-494e6c25.entry.js +2 -0
- package/dist/huibo-ui/p-494e6c25.entry.js.map +1 -0
- package/dist/huibo-ui/p-4d87d7f4.entry.js +2 -0
- package/dist/huibo-ui/p-4d87d7f4.entry.js.map +1 -0
- package/dist/huibo-ui/p-5e253c15.entry.js +2 -0
- package/dist/huibo-ui/p-5e253c15.entry.js.map +1 -0
- package/dist/huibo-ui/p-63d68c61.entry.js +2 -0
- package/dist/huibo-ui/p-63d68c61.entry.js.map +1 -0
- package/dist/huibo-ui/{p-ccd09d5a.entry.js → p-6518c435.entry.js} +2 -2
- package/dist/huibo-ui/{p-1f8db37a.entry.js → p-687d8dff.entry.js} +2 -2
- package/dist/huibo-ui/p-687d8dff.entry.js.map +1 -0
- package/dist/huibo-ui/p-688460ce.entry.js +2 -0
- package/dist/huibo-ui/p-688460ce.entry.js.map +1 -0
- package/dist/huibo-ui/p-69bb1dd9.entry.js +2 -0
- package/dist/huibo-ui/p-69bb1dd9.entry.js.map +1 -0
- package/dist/huibo-ui/{p-2811e603.entry.js → p-6bfe1954.entry.js} +2 -2
- package/dist/huibo-ui/p-6bfe1954.entry.js.map +1 -0
- package/dist/huibo-ui/{p-e5cbfa9e.entry.js → p-6c23fbd1.entry.js} +2 -2
- package/dist/huibo-ui/p-6c23fbd1.entry.js.map +1 -0
- package/dist/huibo-ui/p-6c8cf248.entry.js.map +1 -1
- package/dist/huibo-ui/p-6efed295.entry.js +2 -0
- package/dist/huibo-ui/p-6efed295.entry.js.map +1 -0
- package/dist/huibo-ui/p-7a38b3e2.entry.js +2 -0
- package/dist/huibo-ui/p-7a38b3e2.entry.js.map +1 -0
- package/dist/huibo-ui/{p-cad57c2d.entry.js → p-7a682c56.entry.js} +2 -2
- package/dist/huibo-ui/{p-a8996d22.entry.js → p-815fc943.entry.js} +2 -2
- package/dist/huibo-ui/{p-af74667d.entry.js → p-89be7973.entry.js} +2 -2
- package/dist/huibo-ui/p-8a202bc5.entry.js.map +1 -1
- package/dist/huibo-ui/{p-213b9de7.entry.js → p-8c4415ed.entry.js} +2 -2
- package/dist/huibo-ui/p-8c4415ed.entry.js.map +1 -0
- package/dist/huibo-ui/{p-8fdbd17c.entry.js → p-950e7465.entry.js} +2 -2
- package/dist/huibo-ui/{p-ab9cf0e4.entry.js → p-96cecd21.entry.js} +2 -2
- package/dist/huibo-ui/p-96cecd21.entry.js.map +1 -0
- package/dist/huibo-ui/{p-2b4556ff.entry.js → p-98b513cd.entry.js} +2 -2
- package/dist/huibo-ui/p-98b513cd.entry.js.map +1 -0
- package/dist/huibo-ui/{p-89ea1141.entry.js → p-ac45291c.entry.js} +2 -2
- package/dist/huibo-ui/{p-e10fcfbe.entry.js → p-b105cf76.entry.js} +2 -2
- package/dist/huibo-ui/p-b105cf76.entry.js.map +1 -0
- package/dist/huibo-ui/{p-9a5406f0.entry.js → p-b38802b0.entry.js} +2 -2
- package/dist/huibo-ui/{p-9a5406f0.entry.js.map → p-b38802b0.entry.js.map} +1 -1
- package/dist/huibo-ui/{p-ea74fcae.entry.js → p-b3fd12c7.entry.js} +2 -2
- package/dist/huibo-ui/p-b3fd12c7.entry.js.map +1 -0
- package/dist/huibo-ui/p-b5ea18ba.entry.js +2 -0
- package/dist/huibo-ui/p-b5ea18ba.entry.js.map +1 -0
- package/dist/huibo-ui/{p-41d9c846.entry.js → p-b6afe81e.entry.js} +2 -2
- package/dist/huibo-ui/p-b7900dee.entry.js +2 -0
- package/dist/huibo-ui/p-b7900dee.entry.js.map +1 -0
- package/dist/huibo-ui/p-b8c83751.entry.js +2 -0
- package/dist/huibo-ui/p-b8c83751.entry.js.map +1 -0
- package/dist/huibo-ui/p-c7713947.entry.js +2 -0
- package/dist/huibo-ui/p-c7713947.entry.js.map +1 -0
- package/dist/huibo-ui/{p-33de6878.entry.js → p-c869842c.entry.js} +2 -2
- package/dist/huibo-ui/p-c869842c.entry.js.map +1 -0
- package/dist/huibo-ui/p-c8e917db.entry.js.map +1 -1
- package/dist/huibo-ui/p-cb66dbef.entry.js +2 -0
- package/dist/huibo-ui/p-cb66dbef.entry.js.map +1 -0
- package/dist/huibo-ui/p-cde83f76.entry.js +2 -0
- package/dist/huibo-ui/p-cde83f76.entry.js.map +1 -0
- package/dist/huibo-ui/{p-f5969181.entry.js → p-dd9c6459.entry.js} +2 -2
- package/dist/huibo-ui/{p-08b4005c.js → p-e0876aca.js} +1 -1
- package/dist/huibo-ui/p-e0876aca.js.map +1 -0
- package/dist/huibo-ui/{p-aa5e5e02.entry.js → p-e1773c93.entry.js} +2 -2
- package/dist/huibo-ui/p-e1773c93.entry.js.map +1 -0
- package/dist/huibo-ui/{p-626b48f1.entry.js → p-e73c357f.entry.js} +2 -2
- package/dist/huibo-ui/p-e73c357f.entry.js.map +1 -0
- package/dist/huibo-ui/{p-60532a1f.entry.js → p-e7c73624.entry.js} +2 -2
- package/dist/huibo-ui/p-e7c73624.entry.js.map +1 -0
- package/dist/huibo-ui/{p-86bdc48a.entry.js → p-e8824b2c.entry.js} +2 -2
- package/dist/huibo-ui/p-e8824b2c.entry.js.map +1 -0
- package/dist/huibo-ui/{p-13010da2.entry.js → p-e9e7abca.entry.js} +2 -2
- package/dist/huibo-ui/{p-f6889710.entry.js → p-ea0823f3.entry.js} +2 -2
- package/dist/huibo-ui/p-ea0823f3.entry.js.map +1 -0
- package/dist/huibo-ui/{p-b468858e.entry.js → p-f1f2483f.entry.js} +2 -2
- package/dist/huibo-ui/p-f69599fa.entry.js +2 -0
- package/dist/huibo-ui/p-f69599fa.entry.js.map +1 -0
- package/dist/huibo-ui/p-fad66d69.js +2 -0
- package/dist/huibo-ui/p-fad66d69.js.map +1 -0
- package/dist/huibo-ui/{p-fd8301c6.entry.js → p-fd6831f9.entry.js} +2 -2
- package/dist/huibo-ui/p-ff6bc5cc.entry.js +2 -0
- package/dist/huibo-ui/p-ff6bc5cc.entry.js.map +1 -0
- package/dist/types/components/Cascader/Cascader.d.ts +12 -0
- package/dist/types/components/Checkbox/Checkbox.d.ts +5 -0
- package/dist/types/components/Checkbox/CheckboxGroup.d.ts +1 -0
- package/dist/types/components/Collapse/Collapse.d.ts +2 -0
- package/dist/types/components/Collapse/CollapseItem.d.ts +8 -1
- package/dist/types/components/Dialog/Dialog.d.ts +13 -1
- package/dist/types/components/Drawer/Drawer.d.ts +4 -0
- package/dist/types/components/Dropdown/Dropdown.d.ts +6 -2
- package/dist/types/components/Form/Form.d.ts +59 -0
- package/dist/types/components/Form/FormItem.d.ts +23 -0
- package/dist/types/components/Image/Image.d.ts +6 -0
- package/dist/types/components/Menu/MenuItem.d.ts +8 -1
- package/dist/types/components/Message/Message.d.ts +3 -0
- package/dist/types/components/Popconfirm/Popconfirm.d.ts +6 -2
- package/dist/types/components/Popover/Popover.d.ts +6 -1
- package/dist/types/components/Radio/Radio.d.ts +5 -0
- package/dist/types/components/Segmented/Segmented.d.ts +6 -0
- package/dist/types/components/Select/Select.d.ts +24 -0
- package/dist/types/components/Table/Table.d.ts +110 -9
- package/dist/types/components/Tabs/Tabs.d.ts +6 -0
- package/dist/types/components/Tooltip/Tooltip.d.ts +6 -0
- package/dist/types/components/Tree/Tree.d.ts +24 -0
- package/dist/types/components/TreeSelect/TreeSelect.d.ts +17 -0
- package/dist/types/components/Watermark/Watermark.d.ts +7 -1
- package/dist/types/components.d.ts +188 -6
- package/dist/types/utils/a11y.d.ts +9 -0
- package/dist/types/utils/transition.d.ts +27 -0
- package/dist/types/utils/virtual-scroll.d.ts +38 -0
- package/package.json +1 -1
- package/dist/cjs/a11y-802de67a.js.map +0 -1
- package/dist/cjs/date-helpers-1ffddc59.js.map +0 -1
- package/dist/components/p-08b4005c.js.map +0 -1
- package/dist/components/p-cc0aeb50.js.map +0 -1
- package/dist/esm/a11y-f9ab2964.js.map +0 -1
- package/dist/esm/date-helpers-44507189.js.map +0 -1
- package/dist/huibo-ui/p-08b4005c.js.map +0 -1
- package/dist/huibo-ui/p-1f8db37a.entry.js.map +0 -1
- package/dist/huibo-ui/p-213b9de7.entry.js.map +0 -1
- package/dist/huibo-ui/p-25fd7d5c.entry.js +0 -2
- package/dist/huibo-ui/p-25fd7d5c.entry.js.map +0 -1
- package/dist/huibo-ui/p-2811e603.entry.js.map +0 -1
- package/dist/huibo-ui/p-2943f5d0.entry.js +0 -2
- package/dist/huibo-ui/p-2943f5d0.entry.js.map +0 -1
- package/dist/huibo-ui/p-2b4556ff.entry.js.map +0 -1
- package/dist/huibo-ui/p-33de6878.entry.js.map +0 -1
- package/dist/huibo-ui/p-3807da71.entry.js +0 -2
- package/dist/huibo-ui/p-3807da71.entry.js.map +0 -1
- package/dist/huibo-ui/p-47ef7a86.entry.js +0 -2
- package/dist/huibo-ui/p-47ef7a86.entry.js.map +0 -1
- package/dist/huibo-ui/p-4d34e43e.entry.js +0 -2
- package/dist/huibo-ui/p-4d34e43e.entry.js.map +0 -1
- package/dist/huibo-ui/p-54aa2fd8.entry.js +0 -2
- package/dist/huibo-ui/p-54aa2fd8.entry.js.map +0 -1
- package/dist/huibo-ui/p-60532a1f.entry.js.map +0 -1
- package/dist/huibo-ui/p-626b48f1.entry.js.map +0 -1
- package/dist/huibo-ui/p-639f167d.entry.js +0 -2
- package/dist/huibo-ui/p-639f167d.entry.js.map +0 -1
- package/dist/huibo-ui/p-6beb5b81.entry.js.map +0 -1
- package/dist/huibo-ui/p-735bceef.entry.js.map +0 -1
- package/dist/huibo-ui/p-76519752.entry.js +0 -2
- package/dist/huibo-ui/p-76519752.entry.js.map +0 -1
- package/dist/huibo-ui/p-79af2efa.entry.js +0 -2
- package/dist/huibo-ui/p-79af2efa.entry.js.map +0 -1
- package/dist/huibo-ui/p-7f6975ad.entry.js +0 -2
- package/dist/huibo-ui/p-7f6975ad.entry.js.map +0 -1
- package/dist/huibo-ui/p-86bdc48a.entry.js.map +0 -1
- package/dist/huibo-ui/p-8a8443b8.entry.js +0 -2
- package/dist/huibo-ui/p-8a8443b8.entry.js.map +0 -1
- package/dist/huibo-ui/p-8fd788c9.entry.js +0 -2
- package/dist/huibo-ui/p-8fd788c9.entry.js.map +0 -1
- package/dist/huibo-ui/p-92521c31.entry.js +0 -2
- package/dist/huibo-ui/p-92521c31.entry.js.map +0 -1
- package/dist/huibo-ui/p-965d4d02.entry.js +0 -2
- package/dist/huibo-ui/p-965d4d02.entry.js.map +0 -1
- package/dist/huibo-ui/p-aa5e5e02.entry.js.map +0 -1
- package/dist/huibo-ui/p-ab9cf0e4.entry.js.map +0 -1
- package/dist/huibo-ui/p-b8d87f7e.entry.js.map +0 -1
- package/dist/huibo-ui/p-c6c91664.entry.js +0 -2
- package/dist/huibo-ui/p-c6c91664.entry.js.map +0 -1
- package/dist/huibo-ui/p-c80f8ace.entry.js.map +0 -1
- package/dist/huibo-ui/p-cc0aeb50.js +0 -2
- package/dist/huibo-ui/p-cc0aeb50.js.map +0 -1
- package/dist/huibo-ui/p-d79a15b1.entry.js +0 -2
- package/dist/huibo-ui/p-d79a15b1.entry.js.map +0 -1
- package/dist/huibo-ui/p-e10fcfbe.entry.js.map +0 -1
- package/dist/huibo-ui/p-e5cbfa9e.entry.js.map +0 -1
- package/dist/huibo-ui/p-ea74fcae.entry.js.map +0 -1
- package/dist/huibo-ui/p-edbda423.entry.js +0 -2
- package/dist/huibo-ui/p-edbda423.entry.js.map +0 -1
- package/dist/huibo-ui/p-f6889710.entry.js.map +0 -1
- package/dist/huibo-ui/p-f9bb5217.entry.js +0 -2
- package/dist/huibo-ui/p-f9bb5217.entry.js.map +0 -1
- package/dist/huibo-ui/p-fea20295.entry.js +0 -2
- package/dist/huibo-ui/p-fea20295.entry.js.map +0 -1
- /package/dist/huibo-ui/{p-678b4212.entry.js.map → p-0ddae4e9.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-f4336be9.entry.js.map → p-14c3b47b.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-c50ad398.entry.js.map → p-193efdc0.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-0d4b2997.entry.js.map → p-2bcda1bb.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-7da14d7c.entry.js.map → p-3042f986.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-e039155d.entry.js.map → p-3dacb26b.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-a084b8e5.entry.js.map → p-412ff618.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-ccd09d5a.entry.js.map → p-6518c435.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-cad57c2d.entry.js.map → p-7a682c56.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-a8996d22.entry.js.map → p-815fc943.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-af74667d.entry.js.map → p-89be7973.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-8fdbd17c.entry.js.map → p-950e7465.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-89ea1141.entry.js.map → p-ac45291c.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-41d9c846.entry.js.map → p-b6afe81e.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-f5969181.entry.js.map → p-dd9c6459.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-13010da2.entry.js.map → p-e9e7abca.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-b468858e.entry.js.map → p-f1f2483f.entry.js.map} +0 -0
- /package/dist/huibo-ui/{p-fd8301c6.entry.js.map → p-fd6831f9.entry.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"file":"hb-dropdown.entry.cjs.js","mappings":"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","names":["createClickOutsideHandler","isActivationKey","handleListKeyboard","h","getNextZIndex","index"],"sources":["src/components/Dropdown/dropdown.css?tag=hb-dropdown&encapsulation=shadow","src/components/Dropdown/Dropdown.tsx"],"sourcesContent":[":host {\n display: inline-block;\n position: relative;\n}\n\n.hb-dropdown__trigger {\n display: inline-block;\n cursor: pointer;\n}\n\n.hb-dropdown__menu {\n position: absolute;\n top: 100%;\n left: 0;\n min-width: 120px;\n margin-top: 4px;\n padding: 4px 0;\n background-color: var(--hb-color-bg-elevated);\n border-radius: var(--hb-border-radius-base);\n box-shadow: var(--hb-box-shadow);\n animation: hb-dropdown-fade-in 0.15s ease-out;\n}\n\n.hb-dropdown__item {\n display: flex;\n align-items: center;\n padding: 6px 16px;\n font-size: var(--hb-font-size-sm);\n color: var(--hb-color-text);\n cursor: pointer;\n white-space: nowrap;\n transition: background-color var(--hb-transition-duration);\n}\n\n.hb-dropdown__item:hover:not(.hb-dropdown__item--disabled),\n.hb-dropdown__item--active:not(.hb-dropdown__item--disabled) {\n background-color: var(--hb-color-fill-tertiary);\n color: var(--hb-color-primary);\n}\n\n.hb-dropdown__item--disabled {\n color: var(--hb-color-text-disabled);\n cursor: not-allowed;\n}\n\n.hb-dropdown__item--divided {\n margin-top: 4px;\n padding-top: 8px;\n border-top: 1px solid var(--hb-color-border-secondary);\n}\n\n.hb-dropdown__item--danger {\n color: var(--hb-color-danger);\n}\n.hb-dropdown__item--danger:hover:not(.hb-dropdown__item--disabled) {\n background-color: var(--hb-color-danger-bg);\n color: var(--hb-color-danger);\n}\n\n@keyframes hb-dropdown-fade-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n","import { Component, h, Prop, State, Element, Event, EventEmitter } from '@stencil/core';\nimport { createClickOutsideHandler } from '../../utils/click-outside';\nimport { getNextZIndex } from '../../utils/popup-manager';\nimport { handleListKeyboard, isActivationKey } from '../../utils/a11y';\n\nexport interface DropdownItem {\n key: string;\n label: string;\n disabled?: boolean;\n divided?: boolean;\n danger?: boolean;\n}\n\n/**\n * Dropdown 下拉菜单组件\n * 将动作或菜单折叠到下拉菜单中。\n *\n * 无障碍(对齐 WAI-ARIA menu / antd):\n * - 触发器 role=button + aria-haspopup=menu + aria-expanded\n * - 菜单 role=menu,菜单项 role=menuitem + aria-disabled\n * - 键盘:trigger 上 Enter/Space/↓ 打开;菜单内 ↑↓ 导航、Enter/Space 选中、Esc 关闭\n */\n@Component({\n tag: 'hb-dropdown',\n styleUrl: 'dropdown.css',\n shadow: true,\n})\nexport class Dropdown {\n @Element() el: HTMLElement;\n\n /** 菜单项 */\n @Prop() items: DropdownItem[] = [];\n\n /** 触发方式 */\n @Prop() trigger: 'hover' | 'click' = 'hover';\n\n /** 是否禁用 */\n @Prop() disabled: boolean = false;\n\n @State() isOpen: boolean = false;\n /** 键盘高亮项索引(-1 表示无) */\n @State() activeIndex: number = -1;\n\n /** 命令事件 */\n @Event() hbCommand: EventEmitter<string>;\n\n private clickOutside = createClickOutsideHandler({\n host: null as any,\n isOpen: () => this.isOpen,\n onClose: () => { this.isOpen = false; },\n });\n\n componentDidLoad() {\n this.clickOutside = createClickOutsideHandler({\n host: this.el,\n isOpen: () => this.isOpen,\n onClose: () => { this.close(); },\n });\n // click 触发才需要外部点击关闭;hover 触发由 mouseenter/leave 控制\n if (this.trigger === 'click') {\n this.clickOutside.connect();\n }\n }\n\n disconnectedCallback() {\n this.clickOutside.disconnect();\n }\n\n private open = () => {\n if (this.disabled) return;\n this.isOpen = true;\n // 打开时默认高亮首个可选(非禁用)项,便于 Enter 直接选\n this.activeIndex = this.items.findIndex(i => !i.disabled);\n };\n\n private close = () => {\n this.isOpen = false;\n this.activeIndex = -1;\n };\n\n private show = () => {\n if (this.disabled) return;\n this.isOpen = true;\n };\n\n private hide = () => {\n this.close();\n };\n\n private toggle = () => {\n if (this.disabled) return;\n if (this.isOpen) this.close();\n else this.open();\n };\n\n private handleSelect = (item: DropdownItem) => {\n if (item.disabled) return;\n this.close();\n this.hbCommand.emit(item.key);\n };\n\n /** 触发器键盘:Enter/Space/↓ 打开 */\n private handleTriggerKeydown = (e: KeyboardEvent) => {\n if (this.disabled) return;\n if (this.trigger === 'hover') return; // hover 触发不需要键盘打开(focus 会展开见下)\n if (isActivationKey(e.key) || e.key === 'ArrowDown') {\n e.preventDefault();\n this.open();\n }\n };\n\n /** 菜单键盘:↑↓ 导航、Enter/Space 选中、Esc 关闭、Home/End 跳首尾 */\n private handleMenuKeydown = (e: KeyboardEvent) => {\n const enabledCount = this.items.length;\n const action = handleListKeyboard(e, {\n activeIndex: this.activeIndex,\n itemCount: enabledCount,\n loop: true,\n });\n switch (action.type) {\n case 'navigate':\n e.preventDefault();\n // 跳过禁用项:最多扫一圈\n {\n let idx = action.index;\n for (let i = 0; i < enabledCount; i++) {\n if (!this.items[idx]?.disabled) break;\n idx = (idx + 1) % enabledCount;\n }\n this.activeIndex = idx;\n }\n break;\n case 'select': {\n e.preventDefault();\n const item = this.items[action.index];\n if (item && !item.disabled) this.handleSelect(item);\n break;\n }\n case 'close':\n e.preventDefault();\n this.close();\n break;\n default:\n break;\n }\n };\n\n render() {\n const triggerEvents = this.trigger === 'hover'\n ? { onMouseEnter: this.show, onMouseLeave: this.hide }\n : { onClick: this.toggle };\n\n return (\n <div\n class=\"hb-dropdown\"\n {...triggerEvents}\n onKeyDown={this.handleTriggerKeydown}\n >\n <div\n class=\"hb-dropdown__trigger\"\n role=\"button\"\n tabindex={this.disabled ? -1 : 0}\n aria-haspopup=\"menu\"\n aria-expanded={this.isOpen ? 'true' : 'false'}\n aria-disabled={this.disabled ? 'true' : 'false'}\n >\n <slot />\n </div>\n {this.isOpen && (\n <div\n class=\"hb-dropdown__menu\"\n style={{ zIndex: String(getNextZIndex()) }}\n role=\"menu\"\n onKeyDown={this.handleMenuKeydown}\n >\n {this.items.map((item, index) => (\n <div\n class={{\n 'hb-dropdown__item': true,\n 'hb-dropdown__item--disabled': item.disabled,\n 'hb-dropdown__item--divided': item.divided,\n 'hb-dropdown__item--danger': item.danger,\n 'hb-dropdown__item--active': index === this.activeIndex,\n }}\n role=\"menuitem\"\n tabindex={-1}\n aria-disabled={item.disabled ? 'true' : undefined}\n onMouseEnter={() => { if (!item.disabled) this.activeIndex = index; }}\n onClick={() => this.handleSelect(item)}\n >\n {item.label}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n }\n}\n"],"version":3}
|
|
1
|
+
{"file":"hb-dropdown.entry.cjs.js","mappings":"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","names":["createLeaveScheduler","createClickOutsideHandler","isActivationKey","handleListKeyboard","h","getNextZIndex","index"],"sources":["src/components/Dropdown/dropdown.css?tag=hb-dropdown&encapsulation=shadow","src/components/Dropdown/Dropdown.tsx"],"sourcesContent":[":host {\n display: inline-block;\n position: relative;\n}\n\n.hb-dropdown__trigger {\n display: inline-block;\n cursor: pointer;\n}\n\n.hb-dropdown__menu {\n position: absolute;\n top: 100%;\n left: 0;\n min-width: 120px;\n margin-top: 4px;\n padding: 4px 0;\n background-color: var(--hb-color-bg-elevated);\n border-radius: var(--hb-border-radius-base);\n box-shadow: var(--hb-box-shadow);\n animation: hb-dropdown-fade-in 0.15s ease-out;\n}\n\n.hb-dropdown__item {\n display: flex;\n align-items: center;\n padding: 6px 16px;\n font-size: var(--hb-font-size-sm);\n color: var(--hb-color-text);\n cursor: pointer;\n white-space: nowrap;\n transition: background-color var(--hb-transition-duration);\n}\n\n.hb-dropdown__item:hover:not(.hb-dropdown__item--disabled),\n.hb-dropdown__item--active:not(.hb-dropdown__item--disabled) {\n background-color: var(--hb-color-fill-tertiary);\n color: var(--hb-color-primary);\n}\n\n.hb-dropdown__item--disabled {\n color: var(--hb-color-text-disabled);\n cursor: not-allowed;\n}\n\n.hb-dropdown__item--divided {\n margin-top: 4px;\n padding-top: 8px;\n border-top: 1px solid var(--hb-color-border-secondary);\n}\n\n.hb-dropdown__item--danger {\n color: var(--hb-color-danger);\n}\n.hb-dropdown__item--danger:hover:not(.hb-dropdown__item--disabled) {\n background-color: var(--hb-color-danger-bg);\n color: var(--hb-color-danger);\n}\n\n@keyframes hb-dropdown-fade-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* 离场动画 */\n.hb-dropdown__menu--leaving {\n animation: hb-dropdown-fade-out 0.15s ease-in forwards;\n}\n\n@keyframes hb-dropdown-fade-out {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(-4px);\n }\n}\n","import { Component, h, Prop, State, Element, Event, EventEmitter } from '@stencil/core';\nimport { createClickOutsideHandler } from '../../utils/click-outside';\nimport { getNextZIndex } from '../../utils/popup-manager';\nimport { handleListKeyboard, isActivationKey } from '../../utils/a11y';\nimport { createLeaveScheduler } from '../../utils/transition';\n\nexport interface DropdownItem {\n key: string;\n label: string;\n disabled?: boolean;\n divided?: boolean;\n danger?: boolean;\n}\n\n/**\n * Dropdown 下拉菜单组件\n * 将动作或菜单折叠到下拉菜单中。\n *\n * 无障碍(对齐 WAI-ARIA menu / antd):\n * - 触发器 role=button + aria-haspopup=menu + aria-expanded\n * - 菜单 role=menu,菜单项 role=menuitem + aria-disabled\n * - 键盘:trigger 上 Enter/Space/↓ 打开;菜单内 ↑↓ 导航、Enter/Space 选中、Esc 关闭\n *\n * 进出场动画:用 leaving state 延迟卸载,让 fade-out 有机会播放。\n */\n@Component({\n tag: 'hb-dropdown',\n styleUrl: 'dropdown.css',\n shadow: true,\n})\nexport class Dropdown {\n @Element() el: HTMLElement;\n\n /** 菜单项 */\n @Prop() items: DropdownItem[] = [];\n\n /** 触发方式 */\n @Prop() trigger: 'hover' | 'click' = 'hover';\n\n /** 是否禁用 */\n @Prop() disabled: boolean = false;\n\n @State() isOpen: boolean = false;\n /** 离场动画期(保留 DOM 让 fade-out 播完) */\n @State() leaving: boolean = false;\n /** 键盘高亮项索引(-1 表示无) */\n @State() activeIndex: number = -1;\n\n /** 命令事件 */\n @Event() hbCommand: EventEmitter<string>;\n\n private leave = createLeaveScheduler(\n () => this.leaving,\n v => (this.leaving = v),\n 150,\n );\n\n private clickOutside = createClickOutsideHandler({\n host: null as any,\n isOpen: () => this.isOpen,\n onClose: () => {\n this.close();\n },\n });\n\n componentDidLoad() {\n this.clickOutside = createClickOutsideHandler({\n host: this.el,\n isOpen: () => this.isOpen,\n onClose: () => {\n this.close();\n },\n });\n if (this.trigger === 'click') {\n this.clickOutside.connect();\n }\n }\n\n disconnectedCallback() {\n this.clickOutside.disconnect();\n this.leave.dispose();\n }\n\n private open = () => {\n if (this.disabled) return;\n this.leave.cancel(); // 中途又打开:取消挂起的离场\n this.isOpen = true;\n this.activeIndex = this.items.findIndex(i => !i.disabled);\n };\n\n private close = () => {\n if (!this.isOpen && !this.leaving) return;\n this.isOpen = false;\n this.activeIndex = -1;\n this.leave.start();\n };\n\n private show = () => {\n if (this.disabled) return;\n this.open();\n };\n\n private hide = () => {\n this.close();\n };\n\n private toggle = () => {\n if (this.disabled) return;\n if (this.isOpen) this.close();\n else this.open();\n };\n\n private handleSelect = (item: DropdownItem) => {\n if (item.disabled) return;\n this.close();\n this.hbCommand.emit(item.key);\n };\n\n private handleTriggerKeydown = (e: KeyboardEvent) => {\n if (this.disabled) return;\n if (this.trigger === 'hover') return;\n if (isActivationKey(e.key) || e.key === 'ArrowDown') {\n e.preventDefault();\n this.open();\n }\n };\n\n private handleMenuKeydown = (e: KeyboardEvent) => {\n const enabledCount = this.items.length;\n const action = handleListKeyboard(e, {\n activeIndex: this.activeIndex,\n itemCount: enabledCount,\n loop: true,\n });\n switch (action.type) {\n case 'navigate':\n e.preventDefault();\n {\n let idx = action.index;\n for (let i = 0; i < enabledCount; i++) {\n if (!this.items[idx]?.disabled) break;\n idx = (idx + 1) % enabledCount;\n }\n this.activeIndex = idx;\n }\n break;\n case 'select': {\n e.preventDefault();\n const item = this.items[action.index];\n if (item && !item.disabled) this.handleSelect(item);\n break;\n }\n case 'close':\n e.preventDefault();\n this.close();\n break;\n default:\n break;\n }\n };\n\n private get shouldRender(): boolean {\n return this.isOpen || this.leaving;\n }\n\n render() {\n const triggerEvents = this.trigger === 'hover' ? { onMouseEnter: this.show, onMouseLeave: this.hide } : { onClick: this.toggle };\n\n return (\n <div class=\"hb-dropdown\" {...triggerEvents} onKeyDown={this.handleTriggerKeydown}>\n <div\n class=\"hb-dropdown__trigger\"\n role=\"button\"\n tabindex={this.disabled ? -1 : 0}\n aria-haspopup=\"menu\"\n aria-expanded={this.isOpen ? 'true' : 'false'}\n aria-disabled={this.disabled ? 'true' : 'false'}\n >\n <slot />\n </div>\n {this.shouldRender && (\n <div\n class={{\n 'hb-dropdown__menu': true,\n 'hb-dropdown__menu--leaving': this.leaving,\n }}\n style={{ zIndex: String(getNextZIndex()) }}\n role=\"menu\"\n onKeyDown={this.handleMenuKeydown}\n >\n {this.items.map((item, index) => (\n <div\n class={{\n 'hb-dropdown__item': true,\n 'hb-dropdown__item--disabled': item.disabled,\n 'hb-dropdown__item--divided': item.divided,\n 'hb-dropdown__item--danger': item.danger,\n 'hb-dropdown__item--active': index === this.activeIndex,\n }}\n role=\"menuitem\"\n tabindex={-1}\n aria-disabled={item.disabled ? 'true' : undefined}\n onMouseEnter={() => {\n if (!item.disabled) this.activeIndex = index;\n }}\n onClick={() => this.handleSelect(item)}\n >\n {item.label}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n }\n}\n"],"version":3}
|
|
@@ -14,7 +14,7 @@ const Empty = class {
|
|
|
14
14
|
description = '暂无数据';
|
|
15
15
|
image;
|
|
16
16
|
render() {
|
|
17
|
-
return (index.h("div", { key: '
|
|
17
|
+
return (index.h("div", { key: '716385f61e4692d30d9ef0dab2671b4ee4a8381a', class: "hb-empty" }, index.h("div", { key: '39162ccfefa991ae63a59f585e7a91179b64523a', class: "hb-empty__image" }, this.image ? index.h("img", { src: this.image, alt: this.description }) : index.h("span", { class: "hb-empty__icon" }, "\uD83D\uDCED")), index.h("div", { key: '2ada1cc904ba094aaaf863d82ead88b81576590e', class: "hb-empty__description" }, this.description), index.h("div", { key: 'cb573d62ea4d81a66815a27be96617e0a3c3e470', class: "hb-empty__footer" }, index.h("slot", { key: '424ec328528ea66240ae4216e178bfc7f5ba2acd' }))));
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
Empty.style = HbEmptyStyle0;
|
|
@@ -43,11 +43,11 @@ const FloatButton = class {
|
|
|
43
43
|
right: `${this.right}px`,
|
|
44
44
|
bottom: `${this.bottom}px`,
|
|
45
45
|
};
|
|
46
|
-
return (index.h("button", { key: '
|
|
46
|
+
return (index.h("button", { key: '1c3836a10620e871fd54fdcacab8ed447329203f', type: "button", class: {
|
|
47
47
|
'hb-float-button': true,
|
|
48
48
|
[`hb-float-button--${this.type}`]: true,
|
|
49
49
|
[`hb-float-button--${this.shape}`]: true,
|
|
50
|
-
}, style: style, onClick: this.handleClick }, this.icon && index.h("span", { key: '
|
|
50
|
+
}, style: style, onClick: this.handleClick }, this.icon && index.h("span", { key: 'f0eaa8a4e40805f1442a55ec6830e2ed7aa54299', class: "hb-float-button__icon" }, this.icon), this.description && index.h("span", { key: '8f276ce89d0ace7f26ad65bb0d41dc0a4e262a45', class: "hb-float-button__description" }, this.description), this.renderBadge()));
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
FloatButton.style = HbFloatButtonStyle0;
|
|
@@ -24,6 +24,18 @@ const FormItem = class {
|
|
|
24
24
|
rules = [];
|
|
25
25
|
/** 表单尺寸 */
|
|
26
26
|
size = 'default';
|
|
27
|
+
/**
|
|
28
|
+
* F6:手动校验态('success' | 'warning' | 'error' | 'validating' | '')。
|
|
29
|
+
* 设置后覆盖内部校验结果驱动的错误显示(对齐 antd validateStatus)。
|
|
30
|
+
*/
|
|
31
|
+
validateStatus;
|
|
32
|
+
/** F6:手动错误/帮助文案(配合 validateStatus='error' 显示自定义提示) */
|
|
33
|
+
help;
|
|
34
|
+
/**
|
|
35
|
+
* F7:标签栅格占比(1-24)。未设置时用 labelWidth。
|
|
36
|
+
* 对齐 antd labelCol(简化为纯数字栅格,labelCol.span)。
|
|
37
|
+
*/
|
|
38
|
+
labelCol;
|
|
27
39
|
errors = [];
|
|
28
40
|
isvalidating = false;
|
|
29
41
|
/** hb-form 在 componentWillLoad 注册的事件监听;FormItem 在 componentDidLoad 派发,
|
|
@@ -70,6 +82,24 @@ const FormItem = class {
|
|
|
70
82
|
const form = this.el.closest('hb-form');
|
|
71
83
|
return (form && form.labelPosition) || 'right';
|
|
72
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* F4:继承父 hb-form 的 validateMessages(校验提示模板)。
|
|
87
|
+
* 支持占位符 {label}。仅对 rule 未显式指定 message 的规则生效。
|
|
88
|
+
*/
|
|
89
|
+
get resolvedValidateMessages() {
|
|
90
|
+
const form = this.el.closest('hb-form');
|
|
91
|
+
return form && form.validateMessages;
|
|
92
|
+
}
|
|
93
|
+
/** 用模板生成错误文案({label} 替换为字段标签),优先级:rule.message > 模板 > 内置默认 */
|
|
94
|
+
msg(rule, key, fallback) {
|
|
95
|
+
if (rule.message)
|
|
96
|
+
return rule.message;
|
|
97
|
+
const tmpl = this.resolvedValidateMessages;
|
|
98
|
+
const label = this.label || this.prop;
|
|
99
|
+
if (tmpl && tmpl[key])
|
|
100
|
+
return tmpl[key].replace('{label}', label);
|
|
101
|
+
return fallback.replace('{label}', label);
|
|
102
|
+
}
|
|
73
103
|
/**
|
|
74
104
|
* 验证此字段
|
|
75
105
|
*/
|
|
@@ -84,38 +114,33 @@ const FormItem = class {
|
|
|
84
114
|
const errors = [];
|
|
85
115
|
for (const rule of rules) {
|
|
86
116
|
// 必填校验:空字符串 / null / undefined / 空数组均视为"未填"
|
|
87
|
-
const isEmpty = value === undefined ||
|
|
88
|
-
value === null ||
|
|
89
|
-
value === '' ||
|
|
90
|
-
(Array.isArray(value) && value.length === 0);
|
|
117
|
+
const isEmpty = value === undefined || value === null || value === '' || (Array.isArray(value) && value.length === 0);
|
|
91
118
|
if (rule.required && isEmpty) {
|
|
92
|
-
errors.push(rule
|
|
119
|
+
errors.push(this.msg(rule, 'required', `${this.label || this.prop}不能为空`));
|
|
93
120
|
continue;
|
|
94
121
|
}
|
|
95
122
|
// 非必填且为空时,跳过后续格式校验(与 antd 行为一致)
|
|
96
123
|
if (isEmpty)
|
|
97
124
|
continue;
|
|
98
125
|
if (rule.pattern) {
|
|
99
|
-
const ok = typeof rule.pattern === 'string'
|
|
100
|
-
? new RegExp(rule.pattern).test(String(value))
|
|
101
|
-
: rule.pattern.test(String(value));
|
|
126
|
+
const ok = typeof rule.pattern === 'string' ? new RegExp(rule.pattern).test(String(value)) : rule.pattern.test(String(value));
|
|
102
127
|
if (!ok) {
|
|
103
|
-
errors.push(rule
|
|
128
|
+
errors.push(this.msg(rule, 'pattern', `${this.label || this.prop}格式不正确`));
|
|
104
129
|
continue;
|
|
105
130
|
}
|
|
106
131
|
}
|
|
107
132
|
if (rule.type === 'email') {
|
|
108
133
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(value))) {
|
|
109
|
-
errors.push(rule
|
|
134
|
+
errors.push(this.msg(rule, 'email', `${this.label || this.prop}格式不正确`));
|
|
110
135
|
continue;
|
|
111
136
|
}
|
|
112
137
|
}
|
|
113
138
|
if (rule.min !== undefined && typeof value === 'string' && value.length < rule.min) {
|
|
114
|
-
errors.push(rule
|
|
139
|
+
errors.push(this.msg(rule, 'min', `${this.label || this.prop}最少${rule.min}个字符`));
|
|
115
140
|
continue;
|
|
116
141
|
}
|
|
117
142
|
if (rule.max !== undefined && typeof value === 'string' && value.length > rule.max) {
|
|
118
|
-
errors.push(rule
|
|
143
|
+
errors.push(this.msg(rule, 'max', `${this.label || this.prop}最多${rule.max}个字符`));
|
|
119
144
|
continue;
|
|
120
145
|
}
|
|
121
146
|
if (rule.validator) {
|
|
@@ -144,16 +169,42 @@ const FormItem = class {
|
|
|
144
169
|
}
|
|
145
170
|
return undefined;
|
|
146
171
|
};
|
|
172
|
+
/** F6:实际显示的错误文案。手动 help 优先;否则取内部 errors[0] */
|
|
173
|
+
get displayError() {
|
|
174
|
+
if (this.help !== undefined)
|
|
175
|
+
return this.help;
|
|
176
|
+
return this.errors[0] || '';
|
|
177
|
+
}
|
|
178
|
+
/** F6:实际是否显示错误(手动 validateStatus='error' 或内部有错) */
|
|
179
|
+
get showError() {
|
|
180
|
+
if (this.validateStatus === 'error')
|
|
181
|
+
return true;
|
|
182
|
+
if (this.validateStatus === 'success' || this.validateStatus === 'validating')
|
|
183
|
+
return false;
|
|
184
|
+
return this.errors.length > 0;
|
|
185
|
+
}
|
|
147
186
|
render() {
|
|
148
187
|
const labelTop = this.resolvedLabelPosition === 'top';
|
|
149
|
-
|
|
188
|
+
const hasError = this.showError;
|
|
189
|
+
// A4:label 与内容关联。子控件是 slot(id 未知),无法用 label.for;
|
|
190
|
+
// 改用 content 容器 role=group + aria-labelledby 指向 label id,
|
|
191
|
+
// 把 label 语义绑到整组;并用 aria-required / aria-invalid 暴露必填与校验态(读屏可感知,
|
|
192
|
+
// 不再仅靠红色 + 隐藏星号)。
|
|
193
|
+
const labelId = this.label ? `hb-form-item__label-${this.prop || 'x'}` : undefined;
|
|
194
|
+
// F7:labelCol 栅格占比(1-24),未设置时回退 labelWidth
|
|
195
|
+
const labelStyle = this.labelCol
|
|
196
|
+
? { width: `${(this.labelCol / 24) * 100}%` }
|
|
197
|
+
: this.labelWidth
|
|
198
|
+
? { width: this.labelWidth }
|
|
199
|
+
: undefined;
|
|
200
|
+
return (index.h("div", { key: '8c6bd451a2c673a66d3a98b08fdf30ac74f2fb2e', class: {
|
|
150
201
|
'hb-form-item': true,
|
|
151
|
-
'hb-form-item--error':
|
|
152
|
-
'hb-form-item--validating': this.isvalidating,
|
|
202
|
+
'hb-form-item--error': hasError,
|
|
203
|
+
'hb-form-item--validating': this.isvalidating || this.validateStatus === 'validating',
|
|
153
204
|
'hb-form-item--required': this.isRequired,
|
|
154
205
|
'hb-form-item--label-top': labelTop,
|
|
155
206
|
'hb-form-item--label-left': this.resolvedLabelPosition === 'left',
|
|
156
|
-
} }, this.label && (index.h("label", { key: '
|
|
207
|
+
} }, this.label && (index.h("label", { key: '98db5eae626555e4ae442b116bff048189209b5d', id: labelId, class: "hb-form-item__label", style: labelStyle, title: this.label }, this.isRequired && (index.h("span", { key: '05f771e79623e3eeac28fb8b3d100501c5c94f6b', class: "hb-form-item__required", "aria-hidden": "true" }, "*")), this.label)), index.h("div", { key: '3dc24c2eb1f33ed16f14cca93a644ece209d6c13', class: "hb-form-item__content", role: "group", "aria-labelledby": labelId, "aria-required": this.isRequired ? 'true' : undefined, "aria-invalid": hasError ? 'true' : undefined }, index.h("slot", { key: '3a143de305f27a70c5e775a0c24c16da77f7fe3a' }), hasError && (index.h("div", { key: '9d5708648cb0ec43b9c8a274145221ec0edec86e', class: "hb-form-item__error", role: "alert" }, this.displayError)))));
|
|
157
208
|
}
|
|
158
209
|
};
|
|
159
210
|
FormItem.style = HbFormItemStyle0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"file":"hb-form-item.entry.cjs.js","mappings":"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","names":["h"],"sources":["src/components/Form/form-item.css?tag=hb-form-item&encapsulation=shadow","src/components/Form/FormItem.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\n.hb-form-item {\n display: flex;\n align-items: flex-start;\n gap: var(--hb-spacing-sm);\n}\n\n/* label 位置:顶部(对齐 antd label-position=\"top\")——\n 需要 Form 通过 class 下发,但 FormItem 在独立使用时也支持自身包装。\n 这里用 :host([data-label-position=\"top\"]) 兜底,Form 可通过 setting attribute 生效。 */\n:host([data-label-top]) .hb-form-item,\n.hb-form-item--label-top {\n flex-direction: column;\n align-items: stretch;\n gap: var(--hb-spacing-xs);\n}\n\n.hb-form-item__label {\n display: inline-flex;\n align-items: center;\n justify-content: flex-end;\n height: var(--hb-size-default, 32px);\n font-size: var(--hb-font-size-sm, 14px);\n color: var(--hb-color-text);\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n/* label-position=top 时标签左对齐 */\n:host([data-label-top]) .hb-form-item__label,\n.hb-form-item--label-top .hb-form-item__label {\n justify-content: flex-start;\n height: auto;\n padding-bottom: var(--hb-spacing-xxs, 2px);\n}\n\n/* label-position=left 时标签左对齐 */\n.hb-form-item--label-left .hb-form-item__label {\n justify-content: flex-start;\n}\n\n.hb-form-item__required {\n color: var(--hb-color-danger);\n margin-right: 4px;\n font-size: var(--hb-font-size-sm, 14px);\n font-family: SimSun, sans-serif;\n}\n\n.hb-form-item__content {\n flex: 1;\n position: relative;\n min-width: 0;\n}\n\n.hb-form-item__error {\n font-size: var(--hb-font-size-xs, 12px);\n color: var(--hb-color-danger);\n margin-top: 4px;\n line-height: 1.5;\n min-height: 0;\n animation: hb-form-error-fade-in 0.2s ease-out;\n}\n\n@keyframes hb-form-error-fade-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ============================================================\n * 响应式(移动端):小屏强制 label 顶部布局,\n * 避免标签列在窄屏被挤压。覆盖 hb-form-item--label-left/right。\n * ============================================================ */\n@media (max-width: 575.98px) {\n .hb-form-item {\n flex-direction: column !important;\n align-items: stretch !important;\n gap: var(--hb-spacing-xs) !important;\n }\n\n .hb-form-item__label {\n justify-content: flex-start !important;\n height: auto !important;\n padding-bottom: var(--hb-spacing-xxs, 2px) !important;\n }\n}\n","import { Component, h, Prop, State, Element } from '@stencil/core';\n\n/**\n * FormItem 表单项组件\n * 表单中的每一项\n */\n@Component({\n tag: 'hb-form-item',\n styleUrl: 'form-item.css',\n shadow: true,\n})\nexport class FormItem {\n @Element() el: HTMLElement;\n\n /** 字段名 */\n @Prop() prop: string = '';\n\n /** 标签文本 */\n @Prop() label: string = '';\n\n /** 标签宽度 */\n @Prop() labelWidth?: string;\n\n /** 是否必填 */\n @Prop() required: boolean = false;\n\n /** 该表单项的验证规则 */\n @Prop() rules: any[] = [];\n\n /** 表单尺寸 */\n @Prop() size: 'large' | 'default' | 'small' = 'default';\n\n @State() errors: string[] = [];\n @State() isvalidating: boolean = false;\n\n /** hb-form 在 componentWillLoad 注册的事件监听;FormItem 在 componentDidLoad 派发,\n * 但 componentWillLoad 早于子组件的 componentDidLoad,因此注册一定先到。\n * 这里还监听 hbFieldReset,便于 Form.resetFields 主动广播。 */\n\n componentDidLoad() {\n // 向父级 hb-form 注册\n this.el.dispatchEvent(new CustomEvent('hbFormFieldRegister', {\n detail: {\n prop: this.prop,\n validate: this.validate,\n resetValue: this.resetValue,\n getValue: this.getValue,\n },\n bubbles: true,\n composed: true, // 穿越 Shadow DOM 边界(FormItem 自身 shadow -> Form host)\n }));\n\n // 子控件值变化时清错(对齐 antd:合法输入即移除错误提示)\n this.el.addEventListener('hbChange', this.handleChildChange);\n }\n\n disconnectedCallback() {\n this.el.removeEventListener('hbChange', this.handleChildChange);\n }\n\n /** 子控件 hbChange 时,若当前有错误则重新校验以尽早清除错误提示 */\n private handleChildChange = () => {\n if (this.errors.length > 0) {\n void this.validate();\n }\n };\n\n private get formRules(): any[] {\n // 合并 prop 对应的 form rules 和自身 rules\n const form = this.el.closest('hb-form');\n const formLevelRules = form ? (form as any).rules?.[this.prop] || [] : [];\n return [...formLevelRules, ...this.rules];\n }\n\n /** 是否渲染必填星号:显式 required 或任一规则带 required(对齐 antd 自动推断) */\n private get isRequired(): boolean {\n if (this.required) return true;\n return this.formRules.some(r => r && r.required);\n }\n\n /** 继承父 hb-form 的 labelPosition(FormItem 自身无此 prop,避免与 Form 冲突时以 Form 为准) */\n private get resolvedLabelPosition(): 'left' | 'right' | 'top' {\n const form = this.el.closest('hb-form') as any;\n return (form && form.labelPosition) || 'right';\n }\n\n /**\n * 验证此字段\n */\n @Prop() validate = async (): Promise<string[]> => {\n const value = this.getValue();\n const rules = this.formRules;\n\n if (rules.length === 0) {\n this.errors = [];\n return [];\n }\n\n this.isvalidating = true;\n const errors: string[] = [];\n\n for (const rule of rules) {\n // 必填校验:空字符串 / null / undefined / 空数组均视为\"未填\"\n const isEmpty =\n value === undefined ||\n value === null ||\n value === '' ||\n (Array.isArray(value) && value.length === 0);\n if (rule.required && isEmpty) {\n errors.push(rule.message || `${this.label || this.prop}不能为空`);\n continue;\n }\n // 非必填且为空时,跳过后续格式校验(与 antd 行为一致)\n if (isEmpty) continue;\n if (rule.pattern) {\n const ok = typeof rule.pattern === 'string'\n ? new RegExp(rule.pattern).test(String(value))\n : rule.pattern.test(String(value));\n if (!ok) {\n errors.push(rule.message || `${this.label || this.prop}格式不正确`);\n continue;\n }\n }\n if (rule.type === 'email') {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(String(value))) {\n errors.push(rule.message || `${this.label || this.prop}格式不正确`);\n continue;\n }\n }\n if (rule.min !== undefined && typeof value === 'string' && value.length < rule.min) {\n errors.push(rule.message || `${this.label || this.prop}最少${rule.min}个字符`);\n continue;\n }\n if (rule.max !== undefined && typeof value === 'string' && value.length > rule.max) {\n errors.push(rule.message || `${this.label || this.prop}最多${rule.max}个字符`);\n continue;\n }\n if (rule.validator) {\n try {\n await rule.validator(value, this.formRules);\n } catch (err: any) {\n errors.push(err.message || rule.message || `${this.label || this.prop}验证失败`);\n }\n }\n }\n\n this.errors = errors;\n this.isvalidating = false;\n return errors;\n };\n\n @Prop() resetValue = () => {\n this.errors = [];\n };\n\n @Prop() getValue = (): any => {\n // 覆盖所有表单控件:input/select/cascader/date 系列/数字/checkbox/radio/switch/slider/color-picker/rate/upload\n const input = this.el.querySelector(\n 'hb-input, hb-select, hb-cascader, hb-date-picker, hb-date-time-picker, hb-date-range-picker, ' +\n 'hb-input-number, hb-textarea, hb-checkbox, hb-checkbox-group, hb-radio-group, hb-switch, ' +\n 'hb-slider, hb-color-picker, hb-rate, hb-time-picker, hb-time-select',\n );\n if (input) {\n return (input as any).modelValue;\n }\n return undefined;\n };\n\n render() {\n const labelTop = this.resolvedLabelPosition === 'top';\n return (\n <div\n class={{\n 'hb-form-item': true,\n 'hb-form-item--error': this.errors.length > 0,\n 'hb-form-item--validating': this.isvalidating,\n 'hb-form-item--required': this.isRequired,\n 'hb-form-item--label-top': labelTop,\n 'hb-form-item--label-left': this.resolvedLabelPosition === 'left',\n }}\n >\n {this.label && (\n <label\n class=\"hb-form-item__label\"\n style={this.labelWidth ? { width: this.labelWidth } : undefined}\n title={this.label}\n >\n {this.isRequired && (\n <span class=\"hb-form-item__required\" aria-hidden=\"true\">*</span>\n )}\n {this.label}\n </label>\n )}\n <div class=\"hb-form-item__content\">\n <slot />\n {this.errors.length > 0 && (\n <div class=\"hb-form-item__error\" role=\"alert\">{this.errors[0]}</div>\n )}\n </div>\n </div>\n );\n }\n}\n"],"version":3}
|
|
1
|
+
{"file":"hb-form-item.entry.cjs.js","mappings":"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","names":["h"],"sources":["src/components/Form/form-item.css?tag=hb-form-item&encapsulation=shadow","src/components/Form/FormItem.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\n.hb-form-item {\n display: flex;\n align-items: flex-start;\n gap: var(--hb-spacing-sm);\n}\n\n/* label 位置:顶部(对齐 antd label-position=\"top\")——\n 需要 Form 通过 class 下发,但 FormItem 在独立使用时也支持自身包装。\n 这里用 :host([data-label-position=\"top\"]) 兜底,Form 可通过 setting attribute 生效。 */\n:host([data-label-top]) .hb-form-item,\n.hb-form-item--label-top {\n flex-direction: column;\n align-items: stretch;\n gap: var(--hb-spacing-xs);\n}\n\n.hb-form-item__label {\n display: inline-flex;\n align-items: center;\n justify-content: flex-end;\n height: var(--hb-size-default, 32px);\n font-size: var(--hb-font-size-sm, 14px);\n color: var(--hb-color-text);\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n/* label-position=top 时标签左对齐 */\n:host([data-label-top]) .hb-form-item__label,\n.hb-form-item--label-top .hb-form-item__label {\n justify-content: flex-start;\n height: auto;\n padding-bottom: var(--hb-spacing-xxs, 2px);\n}\n\n/* label-position=left 时标签左对齐 */\n.hb-form-item--label-left .hb-form-item__label {\n justify-content: flex-start;\n}\n\n.hb-form-item__required {\n color: var(--hb-color-danger);\n margin-right: 4px;\n font-size: var(--hb-font-size-sm, 14px);\n font-family: SimSun, sans-serif;\n}\n\n.hb-form-item__content {\n flex: 1;\n position: relative;\n min-width: 0;\n}\n\n.hb-form-item__error {\n font-size: var(--hb-font-size-xs, 12px);\n color: var(--hb-color-danger);\n margin-top: 4px;\n line-height: 1.5;\n min-height: 0;\n animation: hb-form-error-fade-in 0.2s ease-out;\n}\n\n@keyframes hb-form-error-fade-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* ============================================================\n * 响应式(移动端):小屏强制 label 顶部布局,\n * 避免标签列在窄屏被挤压。覆盖 hb-form-item--label-left/right。\n * ============================================================ */\n@media (max-width: 575.98px) {\n .hb-form-item {\n flex-direction: column !important;\n align-items: stretch !important;\n gap: var(--hb-spacing-xs) !important;\n }\n\n .hb-form-item__label {\n justify-content: flex-start !important;\n height: auto !important;\n padding-bottom: var(--hb-spacing-xxs, 2px) !important;\n }\n}\n","import { Component, h, Prop, State, Element } from '@stencil/core';\n\n/**\n * FormItem 表单项组件\n * 表单中的每一项\n */\n@Component({\n tag: 'hb-form-item',\n styleUrl: 'form-item.css',\n shadow: true,\n})\nexport class FormItem {\n @Element() el: HTMLElement;\n\n /** 字段名 */\n @Prop() prop: string = '';\n\n /** 标签文本 */\n @Prop() label: string = '';\n\n /** 标签宽度 */\n @Prop() labelWidth?: string;\n\n /** 是否必填 */\n @Prop() required: boolean = false;\n\n /** 该表单项的验证规则 */\n @Prop() rules: any[] = [];\n\n /** 表单尺寸 */\n @Prop() size: 'large' | 'default' | 'small' = 'default';\n\n /**\n * F6:手动校验态('success' | 'warning' | 'error' | 'validating' | '')。\n * 设置后覆盖内部校验结果驱动的错误显示(对齐 antd validateStatus)。\n */\n @Prop() validateStatus?: '' | 'success' | 'warning' | 'error' | 'validating';\n\n /** F6:手动错误/帮助文案(配合 validateStatus='error' 显示自定义提示) */\n @Prop() help?: string;\n\n /**\n * F7:标签栅格占比(1-24)。未设置时用 labelWidth。\n * 对齐 antd labelCol(简化为纯数字栅格,labelCol.span)。\n */\n @Prop() labelCol?: number;\n\n @State() errors: string[] = [];\n @State() isvalidating: boolean = false;\n\n /** hb-form 在 componentWillLoad 注册的事件监听;FormItem 在 componentDidLoad 派发,\n * 但 componentWillLoad 早于子组件的 componentDidLoad,因此注册一定先到。\n * 这里还监听 hbFieldReset,便于 Form.resetFields 主动广播。 */\n\n componentDidLoad() {\n // 向父级 hb-form 注册\n this.el.dispatchEvent(\n new CustomEvent('hbFormFieldRegister', {\n detail: {\n prop: this.prop,\n validate: this.validate,\n resetValue: this.resetValue,\n getValue: this.getValue,\n },\n bubbles: true,\n composed: true, // 穿越 Shadow DOM 边界(FormItem 自身 shadow -> Form host)\n }),\n );\n\n // 子控件值变化时清错(对齐 antd:合法输入即移除错误提示)\n this.el.addEventListener('hbChange', this.handleChildChange);\n }\n\n disconnectedCallback() {\n this.el.removeEventListener('hbChange', this.handleChildChange);\n }\n\n /** 子控件 hbChange 时,若当前有错误则重新校验以尽早清除错误提示 */\n private handleChildChange = () => {\n if (this.errors.length > 0) {\n void this.validate();\n }\n };\n\n private get formRules(): any[] {\n // 合并 prop 对应的 form rules 和自身 rules\n const form = this.el.closest('hb-form');\n const formLevelRules = form ? (form as any).rules?.[this.prop] || [] : [];\n return [...formLevelRules, ...this.rules];\n }\n\n /** 是否渲染必填星号:显式 required 或任一规则带 required(对齐 antd 自动推断) */\n private get isRequired(): boolean {\n if (this.required) return true;\n return this.formRules.some(r => r && r.required);\n }\n\n /** 继承父 hb-form 的 labelPosition(FormItem 自身无此 prop,避免与 Form 冲突时以 Form 为准) */\n private get resolvedLabelPosition(): 'left' | 'right' | 'top' {\n const form = this.el.closest('hb-form') as any;\n return (form && form.labelPosition) || 'right';\n }\n\n /**\n * F4:继承父 hb-form 的 validateMessages(校验提示模板)。\n * 支持占位符 {label}。仅对 rule 未显式指定 message 的规则生效。\n */\n private get resolvedValidateMessages(): Record<string, string> | undefined {\n const form = this.el.closest('hb-form') as any;\n return form && form.validateMessages;\n }\n\n /** 用模板生成错误文案({label} 替换为字段标签),优先级:rule.message > 模板 > 内置默认 */\n private msg(rule: any, key: string, fallback: string): string {\n if (rule.message) return rule.message;\n const tmpl = this.resolvedValidateMessages;\n const label = this.label || this.prop;\n if (tmpl && tmpl[key]) return tmpl[key].replace('{label}', label);\n return fallback.replace('{label}', label);\n }\n\n /**\n * 验证此字段\n */\n @Prop() validate = async (): Promise<string[]> => {\n const value = this.getValue();\n const rules = this.formRules;\n\n if (rules.length === 0) {\n this.errors = [];\n return [];\n }\n\n this.isvalidating = true;\n const errors: string[] = [];\n\n for (const rule of rules) {\n // 必填校验:空字符串 / null / undefined / 空数组均视为\"未填\"\n const isEmpty = value === undefined || value === null || value === '' || (Array.isArray(value) && value.length === 0);\n if (rule.required && isEmpty) {\n errors.push(this.msg(rule, 'required', `${this.label || this.prop}不能为空`));\n continue;\n }\n // 非必填且为空时,跳过后续格式校验(与 antd 行为一致)\n if (isEmpty) continue;\n if (rule.pattern) {\n const ok = typeof rule.pattern === 'string' ? new RegExp(rule.pattern).test(String(value)) : rule.pattern.test(String(value));\n if (!ok) {\n errors.push(this.msg(rule, 'pattern', `${this.label || this.prop}格式不正确`));\n continue;\n }\n }\n if (rule.type === 'email') {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(String(value))) {\n errors.push(this.msg(rule, 'email', `${this.label || this.prop}格式不正确`));\n continue;\n }\n }\n if (rule.min !== undefined && typeof value === 'string' && value.length < rule.min) {\n errors.push(this.msg(rule, 'min', `${this.label || this.prop}最少${rule.min}个字符`));\n continue;\n }\n if (rule.max !== undefined && typeof value === 'string' && value.length > rule.max) {\n errors.push(this.msg(rule, 'max', `${this.label || this.prop}最多${rule.max}个字符`));\n continue;\n }\n if (rule.validator) {\n try {\n await rule.validator(value, this.formRules);\n } catch (err: any) {\n errors.push(err.message || rule.message || `${this.label || this.prop}验证失败`);\n }\n }\n }\n\n this.errors = errors;\n this.isvalidating = false;\n return errors;\n };\n\n @Prop() resetValue = () => {\n this.errors = [];\n };\n\n @Prop() getValue = (): any => {\n // 覆盖所有表单控件:input/select/cascader/date 系列/数字/checkbox/radio/switch/slider/color-picker/rate/upload\n const input = this.el.querySelector(\n 'hb-input, hb-select, hb-cascader, hb-date-picker, hb-date-time-picker, hb-date-range-picker, ' +\n 'hb-input-number, hb-textarea, hb-checkbox, hb-checkbox-group, hb-radio-group, hb-switch, ' +\n 'hb-slider, hb-color-picker, hb-rate, hb-time-picker, hb-time-select',\n );\n if (input) {\n return (input as any).modelValue;\n }\n return undefined;\n };\n\n /** F6:实际显示的错误文案。手动 help 优先;否则取内部 errors[0] */\n private get displayError(): string {\n if (this.help !== undefined) return this.help;\n return this.errors[0] || '';\n }\n\n /** F6:实际是否显示错误(手动 validateStatus='error' 或内部有错) */\n private get showError(): boolean {\n if (this.validateStatus === 'error') return true;\n if (this.validateStatus === 'success' || this.validateStatus === 'validating') return false;\n return this.errors.length > 0;\n }\n\n render() {\n const labelTop = this.resolvedLabelPosition === 'top';\n const hasError = this.showError;\n // A4:label 与内容关联。子控件是 slot(id 未知),无法用 label.for;\n // 改用 content 容器 role=group + aria-labelledby 指向 label id,\n // 把 label 语义绑到整组;并用 aria-required / aria-invalid 暴露必填与校验态(读屏可感知,\n // 不再仅靠红色 + 隐藏星号)。\n const labelId = this.label ? `hb-form-item__label-${this.prop || 'x'}` : undefined;\n // F7:labelCol 栅格占比(1-24),未设置时回退 labelWidth\n const labelStyle = this.labelCol\n ? { width: `${(this.labelCol / 24) * 100}%` }\n : this.labelWidth\n ? { width: this.labelWidth }\n : undefined;\n return (\n <div\n class={{\n 'hb-form-item': true,\n 'hb-form-item--error': hasError,\n 'hb-form-item--validating': this.isvalidating || this.validateStatus === 'validating',\n 'hb-form-item--required': this.isRequired,\n 'hb-form-item--label-top': labelTop,\n 'hb-form-item--label-left': this.resolvedLabelPosition === 'left',\n }}\n >\n {this.label && (\n <label id={labelId} class=\"hb-form-item__label\" style={labelStyle} title={this.label}>\n {this.isRequired && (\n <span class=\"hb-form-item__required\" aria-hidden=\"true\">\n *\n </span>\n )}\n {this.label}\n </label>\n )}\n <div class=\"hb-form-item__content\" role=\"group\" aria-labelledby={labelId} aria-required={this.isRequired ? 'true' : undefined} aria-invalid={hasError ? 'true' : undefined}>\n <slot />\n {hasError && (\n <div class=\"hb-form-item__error\" role=\"alert\">\n {this.displayError}\n </div>\n )}\n </div>\n </div>\n );\n }\n}\n"],"version":3}
|
|
@@ -26,17 +26,104 @@ const Form = class {
|
|
|
26
26
|
size = 'default';
|
|
27
27
|
/** 是否禁用 */
|
|
28
28
|
disabled = false;
|
|
29
|
+
/**
|
|
30
|
+
* F1:初始值(非受控)。挂载后把这些值写到对应字段的子控件 modelValue。
|
|
31
|
+
* key = FormItem 的 prop。
|
|
32
|
+
*/
|
|
33
|
+
initialValues;
|
|
34
|
+
/**
|
|
35
|
+
* F4:校验提示模板。覆盖默认的「{label}不能为空」「{label}格式不正确」等文案。
|
|
36
|
+
* 支持 {label} 占位符。仅对未在 rule.message 显式指定消息的规则生效。
|
|
37
|
+
*/
|
|
38
|
+
validateMessages;
|
|
39
|
+
/**
|
|
40
|
+
* F2:提交且校验通过后的回调。参数为各字段当前值组成的对象。
|
|
41
|
+
* 由表单 submit(form onSubmit)触发——表单内放 type="submit" 的按钮即可。
|
|
42
|
+
*/
|
|
43
|
+
onFinish;
|
|
44
|
+
/**
|
|
45
|
+
* F2:提交且校验失败后的回调。
|
|
46
|
+
*/
|
|
47
|
+
onFinishFailed;
|
|
48
|
+
/**
|
|
49
|
+
* F3:任意字段值变化时的回调。参数为 { prop, value, values }。
|
|
50
|
+
* 由子控件冒泡的 hbChange 触发。
|
|
51
|
+
*/
|
|
52
|
+
onValuesChange;
|
|
29
53
|
fields = [];
|
|
30
54
|
fieldRegistry = new Map();
|
|
31
55
|
// 用 componentWillLoad 而非 componentDidLoad 注册监听器:
|
|
32
56
|
// Stencil 生命周期里子组件(FormItem)的 componentDidLoad 先于父组件(Form)触发,
|
|
33
57
|
// 若在 componentDidLoad 才挂监听,会错过子项派发的 hbFormFieldRegister,
|
|
34
58
|
// 导致 fieldRegistry 为空、validate() 永远返回 true(真实浏览器里复现,mock-doc 被 waitForChanges 掩盖)。
|
|
59
|
+
// L1:抽命名 handler 以便 disconnectedCallback 正确 remove(修复前匿名箭头无法 remove)。
|
|
60
|
+
handleFieldRegister = ((e) => {
|
|
61
|
+
const { prop, validate, resetValue, getValue } = e.detail;
|
|
62
|
+
this.fieldRegistry.set(prop, { prop, validate, resetValue, getValue });
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* F3:监听子控件冒泡的 hbChange,识别来源 FormItem 并触发 onValuesChange。
|
|
66
|
+
* 注:hbChange 由 hb-input/hb-select 等控件发出(composed 冒泡穿过 shadow),
|
|
67
|
+
* 这里在 host 上捕获,通过 closest('hb-form-item') 定位字段 prop。
|
|
68
|
+
*/
|
|
69
|
+
handleFieldChange = ((e) => {
|
|
70
|
+
if (!this.onValuesChange)
|
|
71
|
+
return;
|
|
72
|
+
const target = e.target;
|
|
73
|
+
const item = target.closest?.('hb-form-item');
|
|
74
|
+
if (!item)
|
|
75
|
+
return;
|
|
76
|
+
const prop = item.prop;
|
|
77
|
+
if (!prop)
|
|
78
|
+
return;
|
|
79
|
+
// 取该字段最新值
|
|
80
|
+
const reg = this.fieldRegistry.get(prop);
|
|
81
|
+
const value = reg ? reg.getValue() : undefined;
|
|
82
|
+
this.onValuesChange({ prop, value, values: this.getFieldsValue() });
|
|
83
|
+
});
|
|
35
84
|
componentWillLoad() {
|
|
36
|
-
this.el.addEventListener('hbFormFieldRegister',
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
85
|
+
this.el.addEventListener('hbFormFieldRegister', this.handleFieldRegister);
|
|
86
|
+
// F3:捕获子控件值变化
|
|
87
|
+
this.el.addEventListener('hbChange', this.handleFieldChange);
|
|
88
|
+
}
|
|
89
|
+
componentDidLoad() {
|
|
90
|
+
// F1:把 initialValues 写到对应字段的子控件
|
|
91
|
+
if (this.initialValues) {
|
|
92
|
+
this.fieldRegistry.forEach((_reg, prop) => {
|
|
93
|
+
if (this.initialValues && prop in this.initialValues) {
|
|
94
|
+
this.setFieldValue(prop, this.initialValues[prop]);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
disconnectedCallback() {
|
|
100
|
+
this.el.removeEventListener('hbFormFieldRegister', this.handleFieldRegister);
|
|
101
|
+
this.el.removeEventListener('hbChange', this.handleFieldChange);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 收集所有字段的当前值(getFieldsValue)。
|
|
105
|
+
*/
|
|
106
|
+
getFieldsValue() {
|
|
107
|
+
const values = {};
|
|
108
|
+
this.fieldRegistry.forEach((reg, prop) => {
|
|
109
|
+
values[prop] = reg.getValue();
|
|
110
|
+
});
|
|
111
|
+
return values;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 设置某字段子控件的值(setFieldValue)。
|
|
115
|
+
* 子控件统一用 modelValue 受控。
|
|
116
|
+
*/
|
|
117
|
+
setFieldValue(prop, value) {
|
|
118
|
+
const formItem = this.el.querySelector(`hb-form-item[prop="${prop}"]`);
|
|
119
|
+
if (!formItem)
|
|
120
|
+
return;
|
|
121
|
+
const control = formItem.querySelector('hb-input, hb-select, hb-cascader, hb-date-picker, hb-date-time-picker, hb-date-range-picker, ' +
|
|
122
|
+
'hb-input-number, hb-textarea, hb-checkbox, hb-checkbox-group, hb-radio-group, hb-switch, ' +
|
|
123
|
+
'hb-slider, hb-color-picker, hb-rate, hb-time-picker, hb-time-select');
|
|
124
|
+
if (control) {
|
|
125
|
+
control.modelValue = value;
|
|
126
|
+
}
|
|
40
127
|
}
|
|
41
128
|
/**
|
|
42
129
|
* 验证整个表单
|
|
@@ -49,18 +136,39 @@ const Form = class {
|
|
|
49
136
|
}));
|
|
50
137
|
return results.every(Boolean);
|
|
51
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* F2:提交表单——校验全部字段,通过则 onFinish(values),失败则 onFinishFailed(errors)。
|
|
141
|
+
*/
|
|
142
|
+
handleSubmit = async (e) => {
|
|
143
|
+
e.preventDefault();
|
|
144
|
+
const errorList = [];
|
|
145
|
+
let allOk = true;
|
|
146
|
+
for (const field of this.fieldRegistry.values()) {
|
|
147
|
+
const errors = await field.validate();
|
|
148
|
+
if (errors.length > 0) {
|
|
149
|
+
allOk = false;
|
|
150
|
+
errorList.push({ prop: field.prop, errors });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (allOk) {
|
|
154
|
+
this.onFinish?.(this.getFieldsValue());
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
this.onFinishFailed?.(errorList);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
52
160
|
/**
|
|
53
161
|
* 重置表单
|
|
54
162
|
*/
|
|
55
163
|
resetFields = () => {
|
|
56
|
-
this.fieldRegistry.forEach(
|
|
164
|
+
this.fieldRegistry.forEach(field => field.resetValue());
|
|
57
165
|
};
|
|
58
166
|
render() {
|
|
59
|
-
return (index.h("form", { key: '
|
|
167
|
+
return (index.h("form", { key: '876ec07f044efed1a9aa92dbb76642b95013e9a5', class: {
|
|
60
168
|
'hb-form': true,
|
|
61
169
|
[`hb-form--label-${this.labelPosition}`]: true,
|
|
62
170
|
'hb-form--inline': this.inline,
|
|
63
|
-
}, onSubmit:
|
|
171
|
+
}, onSubmit: this.handleSubmit, novalidate: true }, index.h("slot", { key: '16efaff38a6f97ff1f339eef37f55b7e4aff0f4c' })));
|
|
64
172
|
}
|
|
65
173
|
};
|
|
66
174
|
Form.style = HbFormStyle0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"file":"hb-form.entry.cjs.js","mappings":";;;;;;AAAA,MAAM,OAAO,GAAG,i0LAAi0L,CAAC;AACl1L,qBAAe,OAAO;;MCiBT,IAAI;;;;;;IAIP,KAAK,GAAwB,EAAE,CAAC;;IAGhC,KAAK,GAA0B,EAAE,CAAC;;IAGlC,aAAa,GAA6B,OAAO,CAAC;;IAGlD,UAAU,GAAW,MAAM,CAAC;;IAG5B,MAAM,GAAY,KAAK,CAAC;;IAGxB,IAAI,GAAkC,SAAS,CAAC;;IAGhD,QAAQ,GAAY,KAAK,CAAC;IAEzB,MAAM,GAA4B,EAAE,CAAC;IAEtC,aAAa,GAAG,IAAI,GAAG,EAAiC,CAAC;;;;;IAMjE,iBAAiB;QACf,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,qBAAqB,GAAG,CAAC,CAAc;YAC9D,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;YAC1D,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;SACxE,EAAmB,CAAC;KACtB;;;;;IAMO,QAAQ,GAAG;QACjB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,KAAK;YACtD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAC;YACtC,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;SAC5B,CAAC,CACH,CAAC;QACF,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;KAC/B,CAAC;;;;IAKM,WAAW,GAAG;QACpB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;KAC3D,CAAC;IAEF,MAAM;QACJ,QACEA,mEACE,KAAK,EAAE;gBACL,SAAS,EAAE,IAAI;gBACf,CAAC,kBAAkB,IAAI,CAAC,aAAa,EAAE,GAAG,IAAI;gBAC9C,iBAAiB,EAAE,IAAI,CAAC,MAAM;aAC/B,EACD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,cAAc,EAAE,EACnC,UAAU,UAEVA,oEAAQ,CACH,EACP;KACH;;;;;;","names":["h"],"sources":["src/components/Form/form.css?tag=hb-form&encapsulation=shadow","src/components/Form/Form.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\n.hb-form {\n display: flex;\n flex-direction: column;\n gap: var(--hb-spacing-md);\n}\n\n.hb-form--inline {\n flex-direction: row;\n flex-wrap: wrap;\n gap: var(--hb-spacing-sm) var(--hb-spacing-lg);\n align-items: flex-start;\n}\n","import { Component, h, Prop, State, Element } from '@stencil/core';\n\ninterface FormFieldRegistration {\n prop: string;\n validate: () => Promise<string[]>;\n resetValue: () => void;\n getValue: () => any;\n}\n\n/**\n * Form 表单组件\n * 由输入框、选择器、单选框、多选框等控件组成,配合表单校验\n */\n@Component({\n tag: 'hb-form',\n styleUrl: 'form.css',\n shadow: true,\n})\nexport class Form {\n @Element() el: HTMLElement;\n\n /** 表单数据对象 */\n @Prop() model: Record<string, any> = {};\n\n /** 表单验证规则 */\n @Prop() rules: Record<string, any[]> = {};\n\n /** 标签位置 */\n @Prop() labelPosition: 'left' | 'right' | 'top' = 'right';\n\n /** 标签宽度 */\n @Prop() labelWidth: string = '80px';\n\n /** 是否行内表单 */\n @Prop() inline: boolean = false;\n\n /** 表单尺寸 */\n @Prop() size: 'large' | 'default' | 'small' = 'default';\n\n /** 是否禁用 */\n @Prop() disabled: boolean = false;\n\n @State() fields: FormFieldRegistration[] = [];\n\n private fieldRegistry = new Map<string, FormFieldRegistration>();\n\n // 用 componentWillLoad 而非 componentDidLoad 注册监听器:\n // Stencil 生命周期里子组件(FormItem)的 componentDidLoad 先于父组件(Form)触发,\n // 若在 componentDidLoad 才挂监听,会错过子项派发的 hbFormFieldRegister,\n // 导致 fieldRegistry 为空、validate() 永远返回 true(真实浏览器里复现,mock-doc 被 waitForChanges 掩盖)。\n componentWillLoad() {\n this.el.addEventListener('hbFormFieldRegister', ((e: CustomEvent) => {\n const { prop, validate, resetValue, getValue } = e.detail;\n this.fieldRegistry.set(prop, { prop, validate, resetValue, getValue });\n }) as EventListener);\n }\n\n /**\n * 验证整个表单\n * @returns 是否验证通过\n */\n @Prop() validate = async (): Promise<boolean> => {\n const results = await Promise.all(\n Array.from(this.fieldRegistry.values()).map(async (field) => {\n const errors = await field.validate();\n return errors.length === 0;\n })\n );\n return results.every(Boolean);\n };\n\n /**\n * 重置表单\n */\n @Prop() resetFields = (): void => {\n this.fieldRegistry.forEach((field) => field.resetValue());\n };\n\n render() {\n return (\n <form\n class={{\n 'hb-form': true,\n [`hb-form--label-${this.labelPosition}`]: true,\n 'hb-form--inline': this.inline,\n }}\n onSubmit={(e) => e.preventDefault()}\n novalidate\n >\n <slot />\n </form>\n );\n }\n}\n"],"version":3}
|
|
1
|
+
{"file":"hb-form.entry.cjs.js","mappings":"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","names":["h"],"sources":["src/components/Form/form.css?tag=hb-form&encapsulation=shadow","src/components/Form/Form.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\n.hb-form {\n display: flex;\n flex-direction: column;\n gap: var(--hb-spacing-md);\n}\n\n.hb-form--inline {\n flex-direction: row;\n flex-wrap: wrap;\n gap: var(--hb-spacing-sm) var(--hb-spacing-lg);\n align-items: flex-start;\n}\n","import { Component, h, Prop, State, Element } from '@stencil/core';\n\ninterface FormFieldRegistration {\n prop: string;\n validate: () => Promise<string[]>;\n resetValue: () => void;\n getValue: () => any;\n}\n\n/**\n * Form 表单组件\n * 由输入框、选择器、单选框、多选框等控件组成,配合表单校验\n */\n@Component({\n tag: 'hb-form',\n styleUrl: 'form.css',\n shadow: true,\n})\nexport class Form {\n @Element() el: HTMLElement;\n\n /** 表单数据对象 */\n @Prop() model: Record<string, any> = {};\n\n /** 表单验证规则 */\n @Prop() rules: Record<string, any[]> = {};\n\n /** 标签位置 */\n @Prop() labelPosition: 'left' | 'right' | 'top' = 'right';\n\n /** 标签宽度 */\n @Prop() labelWidth: string = '80px';\n\n /** 是否行内表单 */\n @Prop() inline: boolean = false;\n\n /** 表单尺寸 */\n @Prop() size: 'large' | 'default' | 'small' = 'default';\n\n /** 是否禁用 */\n @Prop() disabled: boolean = false;\n\n /**\n * F1:初始值(非受控)。挂载后把这些值写到对应字段的子控件 modelValue。\n * key = FormItem 的 prop。\n */\n @Prop() initialValues?: Record<string, any>;\n\n /**\n * F4:校验提示模板。覆盖默认的「{label}不能为空」「{label}格式不正确」等文案。\n * 支持 {label} 占位符。仅对未在 rule.message 显式指定消息的规则生效。\n */\n @Prop() validateMessages?: { required?: string; pattern?: string; email?: string; min?: string; max?: string };\n\n /**\n * F2:提交且校验通过后的回调。参数为各字段当前值组成的对象。\n * 由表单 submit(form onSubmit)触发——表单内放 type=\"submit\" 的按钮即可。\n */\n @Prop() onFinish?: (values: Record<string, any>) => void;\n\n /**\n * F2:提交且校验失败后的回调。\n */\n @Prop() onFinishFailed?: (errors: { prop: string; errors: string[] }[]) => void;\n\n /**\n * F3:任意字段值变化时的回调。参数为 { prop, value, values }。\n * 由子控件冒泡的 hbChange 触发。\n */\n @Prop() onValuesChange?: (info: { prop: string; value: any; values: Record<string, any> }) => void;\n\n @State() fields: FormFieldRegistration[] = [];\n\n private fieldRegistry = new Map<string, FormFieldRegistration>();\n\n // 用 componentWillLoad 而非 componentDidLoad 注册监听器:\n // Stencil 生命周期里子组件(FormItem)的 componentDidLoad 先于父组件(Form)触发,\n // 若在 componentDidLoad 才挂监听,会错过子项派发的 hbFormFieldRegister,\n // 导致 fieldRegistry 为空、validate() 永远返回 true(真实浏览器里复现,mock-doc 被 waitForChanges 掩盖)。\n // L1:抽命名 handler 以便 disconnectedCallback 正确 remove(修复前匿名箭头无法 remove)。\n private handleFieldRegister = ((e: CustomEvent) => {\n const { prop, validate, resetValue, getValue } = e.detail;\n this.fieldRegistry.set(prop, { prop, validate, resetValue, getValue });\n }) as EventListener;\n\n /**\n * F3:监听子控件冒泡的 hbChange,识别来源 FormItem 并触发 onValuesChange。\n * 注:hbChange 由 hb-input/hb-select 等控件发出(composed 冒泡穿过 shadow),\n * 这里在 host 上捕获,通过 closest('hb-form-item') 定位字段 prop。\n */\n private handleFieldChange = ((e: Event) => {\n if (!this.onValuesChange) return;\n const target = e.target as HTMLElement;\n const item = target.closest?.('hb-form-item') as any;\n if (!item) return;\n const prop = item.prop;\n if (!prop) return;\n // 取该字段最新值\n const reg = this.fieldRegistry.get(prop);\n const value = reg ? reg.getValue() : undefined;\n this.onValuesChange({ prop, value, values: this.getFieldsValue() });\n }) as EventListener;\n\n componentWillLoad() {\n this.el.addEventListener('hbFormFieldRegister', this.handleFieldRegister);\n // F3:捕获子控件值变化\n this.el.addEventListener('hbChange', this.handleFieldChange);\n }\n\n componentDidLoad() {\n // F1:把 initialValues 写到对应字段的子控件\n if (this.initialValues) {\n this.fieldRegistry.forEach((_reg, prop) => {\n if (this.initialValues && prop in this.initialValues) {\n this.setFieldValue(prop, this.initialValues[prop]);\n }\n });\n }\n }\n\n disconnectedCallback() {\n this.el.removeEventListener('hbFormFieldRegister', this.handleFieldRegister);\n this.el.removeEventListener('hbChange', this.handleFieldChange);\n }\n\n /**\n * 收集所有字段的当前值(getFieldsValue)。\n */\n private getFieldsValue(): Record<string, any> {\n const values: Record<string, any> = {};\n this.fieldRegistry.forEach((reg, prop) => {\n values[prop] = reg.getValue();\n });\n return values;\n }\n\n /**\n * 设置某字段子控件的值(setFieldValue)。\n * 子控件统一用 modelValue 受控。\n */\n private setFieldValue(prop: string, value: any) {\n const formItem = this.el.querySelector(`hb-form-item[prop=\"${prop}\"]`) as HTMLElement | null;\n if (!formItem) return;\n const control = formItem.querySelector(\n 'hb-input, hb-select, hb-cascader, hb-date-picker, hb-date-time-picker, hb-date-range-picker, ' +\n 'hb-input-number, hb-textarea, hb-checkbox, hb-checkbox-group, hb-radio-group, hb-switch, ' +\n 'hb-slider, hb-color-picker, hb-rate, hb-time-picker, hb-time-select',\n ) as any;\n if (control) {\n control.modelValue = value;\n }\n }\n\n /**\n * 验证整个表单\n * @returns 是否验证通过\n */\n @Prop() validate = async (): Promise<boolean> => {\n const results = await Promise.all(\n Array.from(this.fieldRegistry.values()).map(async field => {\n const errors = await field.validate();\n return errors.length === 0;\n }),\n );\n return results.every(Boolean);\n };\n\n /**\n * F2:提交表单——校验全部字段,通过则 onFinish(values),失败则 onFinishFailed(errors)。\n */\n private handleSubmit = async (e: Event) => {\n e.preventDefault();\n const errorList: { prop: string; errors: string[] }[] = [];\n let allOk = true;\n for (const field of this.fieldRegistry.values()) {\n const errors = await field.validate();\n if (errors.length > 0) {\n allOk = false;\n errorList.push({ prop: field.prop, errors });\n }\n }\n if (allOk) {\n this.onFinish?.(this.getFieldsValue());\n } else {\n this.onFinishFailed?.(errorList);\n }\n };\n\n /**\n * 重置表单\n */\n @Prop() resetFields = (): void => {\n this.fieldRegistry.forEach(field => field.resetValue());\n };\n\n render() {\n return (\n <form\n class={{\n 'hb-form': true,\n [`hb-form--label-${this.labelPosition}`]: true,\n 'hb-form--inline': this.inline,\n }}\n onSubmit={this.handleSubmit}\n novalidate\n >\n <slot />\n </form>\n );\n }\n}\n"],"version":3}
|
|
@@ -169,7 +169,7 @@ const ImagePreview = class {
|
|
|
169
169
|
const imgStyle = {
|
|
170
170
|
transform: `scale(${this.zoom}) rotate(${this.rotate}deg)`,
|
|
171
171
|
};
|
|
172
|
-
return (index.h("div", { class: "hb-image-preview", onClick: this.handleOverlayClick }, index.h("div", { class: "hb-image-preview__wrapper" }, index.h("img", { class: "hb-image-preview__img", src: this.currentSrc, alt: "", style: imgStyle, onWheel: this.handleWheel })), this.isMulti && (index.h("button", { type: "button", class: "hb-image-preview__btn hb-image-preview__btn--prev", onClick: this.prev, "aria-label": "\u4E0A\u4E00\u5F20" }, "\u2039")), this.isMulti && (index.h("button", { type: "button", class: "hb-image-preview__btn hb-image-preview__btn--next", onClick: this.next, "aria-label": "\u4E0B\u4E00\u5F20" }, "\u203A")), index.h("div", { class: "hb-image-preview__toolbar", onClick:
|
|
172
|
+
return (index.h("div", { class: "hb-image-preview", onClick: this.handleOverlayClick }, index.h("div", { class: "hb-image-preview__wrapper" }, index.h("img", { class: "hb-image-preview__img", src: this.currentSrc, alt: "", style: imgStyle, onWheel: this.handleWheel })), this.isMulti && (index.h("button", { type: "button", class: "hb-image-preview__btn hb-image-preview__btn--prev", onClick: this.prev, "aria-label": "\u4E0A\u4E00\u5F20" }, "\u2039")), this.isMulti && (index.h("button", { type: "button", class: "hb-image-preview__btn hb-image-preview__btn--next", onClick: this.next, "aria-label": "\u4E0B\u4E00\u5F20" }, "\u203A")), index.h("div", { class: "hb-image-preview__toolbar", onClick: e => e.stopPropagation() }, index.h("button", { type: "button", class: "hb-image-preview__tool", onClick: this.zoomOut, "aria-label": "\u7F29\u5C0F" }, "\uFF0D"), index.h("span", { class: "hb-image-preview__tool-label" }, Math.round(this.zoom * 100), "%"), index.h("button", { type: "button", class: "hb-image-preview__tool", onClick: this.zoomIn, "aria-label": "\u653E\u5927" }, "\uFF0B"), index.h("button", { type: "button", class: "hb-image-preview__tool", onClick: this.handleRotateLeft, "aria-label": "\u5DE6\u65CB" }, "\u21BA"), index.h("button", { type: "button", class: "hb-image-preview__tool", onClick: this.handleRotateRight, "aria-label": "\u53F3\u65CB" }, "\u21BB"), index.h("button", { type: "button", class: "hb-image-preview__tool", onClick: this.handleReset, "aria-label": "\u91CD\u7F6E" }, "\u27F2"), index.h("button", { type: "button", class: "hb-image-preview__tool", onClick: this.stopAndClose, "aria-label": "\u5173\u95ED" }, "\u2715")), index.h("button", { type: "button", class: "hb-image-preview__close", onClick: this.stopAndClose, "aria-label": "\u5173\u95ED" }, "\u00D7")));
|
|
173
173
|
}
|
|
174
174
|
static get watchers() { return {
|
|
175
175
|
"modelValue": ["handleVisibleChange"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"file":"hb-image-preview.entry.cjs.js","mappings":"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","names":["h"],"sources":["src/components/ImagePreview/image-preview.css?tag=hb-image-preview&encapsulation=shadow","src/components/ImagePreview/ImagePreview.tsx"],"sourcesContent":[":host {\n display: contents;\n}\n\n.hb-image-preview {\n position: fixed;\n inset: 0;\n z-index: var(--hb-z-index-modal-mask, 2000);\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--hb-color-bg-mask, rgba(0, 0, 0, 0.5));\n}\n\n.hb-image-preview__wrapper {\n max-width: 90vw;\n max-height: 90vh;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.hb-image-preview__img {\n max-width: 90vw;\n max-height: 90vh;\n object-fit: contain;\n user-select: none;\n transition: transform 0.2s ease;\n pointer-events: none;\n}\n\n.hb-image-preview__btn {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background-color: rgba(0, 0, 0, 0.4);\n color: var(--hb-color-text-inverse, #ffffff);\n font-size: 28px;\n line-height: 1;\n cursor: pointer;\n transition: background-color var(--hb-transition-duration, 0.2s) ease;\n}\n\n.hb-image-preview__btn:hover {\n background-color: rgba(0, 0, 0, 0.6);\n}\n\n.hb-image-preview__btn--prev {\n left: 24px;\n}\n\n.hb-image-preview__btn--next {\n right: 24px;\n}\n\n.hb-image-preview__toolbar {\n position: absolute;\n bottom: 32px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 12px;\n border-radius: var(--hb-border-radius-base, 4px);\n background-color: rgba(0, 0, 0, 0.5);\n color: var(--hb-color-text-inverse, #ffffff);\n}\n\n.hb-image-preview__tool {\n min-width: 32px;\n height: 32px;\n padding: 0 8px;\n border: none;\n border-radius: var(--hb-border-radius-sm, 2px);\n background: transparent;\n color: var(--hb-color-text-inverse, #ffffff);\n font-size: 16px;\n cursor: pointer;\n transition: background-color var(--hb-transition-duration, 0.2s) ease;\n}\n\n.hb-image-preview__tool:hover {\n background-color: rgba(255, 255, 255, 0.15);\n}\n\n.hb-image-preview__tool-label {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 48px;\n padding: 0 4px;\n font-size: 13px;\n color: var(--hb-color-text-inverse, #ffffff);\n}\n\n.hb-image-preview__close {\n position: absolute;\n top: 24px;\n right: 24px;\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background-color: rgba(0, 0, 0, 0.4);\n color: var(--hb-color-text-inverse, #ffffff);\n font-size: 28px;\n line-height: 1;\n cursor: pointer;\n transition: background-color var(--hb-transition-duration, 0.2s) ease;\n}\n\n.hb-image-preview__close:hover {\n background-color: rgba(0, 0, 0, 0.6);\n}\n","import { Component, h, Prop, Event, EventEmitter, State, Watch, Element } from '@stencil/core';\n\nexport interface ImagePreviewChangeDetail {\n src: string;\n index: number;\n}\n\n/**\n * ImagePreview 图片预览组件\n * 点击图片后展示大图,支持缩放、旋转、多图切换\n */\n@Component({\n tag: 'hb-image-preview',\n styleUrl: 'image-preview.css',\n shadow: true,\n})\nexport class ImagePreview {\n @Element() el: HTMLElement;\n\n /** 是否显示预览(受控,可双向) */\n @Prop({ mutable: true }) modelValue: boolean = false;\n\n /** 单图源(srcList 为空时使用) */\n @Prop() src: string = '';\n\n /** 多图源列表 */\n @Prop() srcList: string[] = [];\n\n /** 多图当前索引 */\n @Prop({ mutable: true }) current: number = 0;\n\n /** 单次缩放步长 */\n @Prop() zoomStep: number = 0.2;\n\n /** 最小缩放比例 */\n @Prop() minZoom: number = 0.5;\n\n /** 最大缩放比例 */\n @Prop() maxZoom: number = 3;\n\n /** 关闭事件 */\n @Event() hbClose: EventEmitter<void>;\n\n /** 切换事件,detail 为 { src, index } */\n @Event() hbChange: EventEmitter<ImagePreviewChangeDetail>;\n\n /** 当前缩放比例 */\n @State() zoom: number = 1;\n\n /** 当前旋转角度 */\n @State() rotate: number = 0;\n\n private keyDownHandler = (e: KeyboardEvent) => {\n if (!this.modelValue) return;\n if (e.key === 'Escape') {\n this.close();\n } else if (e.key === 'ArrowLeft') {\n this.prev();\n } else if (e.key === 'ArrowRight') {\n this.next();\n }\n };\n\n @Watch('modelValue')\n handleVisibleChange(newVal: boolean) {\n if (newVal) {\n // 打开时重置缩放与旋转\n this.zoom = 1;\n this.rotate = 0;\n document.addEventListener('keydown', this.keyDownHandler);\n } else {\n document.removeEventListener('keydown', this.keyDownHandler);\n }\n }\n\n @Watch('current')\n handleCurrentChange() {\n // 切换图片时重置变换\n this.zoom = 1;\n this.rotate = 0;\n }\n\n componentDidLoad() {\n if (this.modelValue) {\n document.addEventListener('keydown', this.keyDownHandler);\n }\n }\n\n disconnectedCallback() {\n document.removeEventListener('keydown', this.keyDownHandler);\n }\n\n /** 实际可切换的图片列表 */\n private get imageList(): string[] {\n if (this.srcList && this.srcList.length > 0) {\n return this.srcList;\n }\n return this.src ? [this.src] : [];\n }\n\n private get currentIndex(): number {\n const list = this.imageList;\n if (list.length === 0) return 0;\n if (this.current < 0) return 0;\n if (this.current >= list.length) return list.length - 1;\n return this.current;\n }\n\n private get currentSrc(): string {\n const list = this.imageList;\n if (list.length === 0) return '';\n return list[this.currentIndex] || '';\n }\n\n private get isMulti(): boolean {\n return this.imageList.length > 1;\n }\n\n private close = () => {\n this.modelValue = false;\n this.hbClose.emit();\n };\n\n private emitChange() {\n this.hbChange.emit({ src: this.currentSrc, index: this.currentIndex });\n }\n\n private next = () => {\n const list = this.imageList;\n if (list.length <= 1) return;\n this.current = (this.currentIndex + 1) % list.length;\n this.emitChange();\n };\n\n private prev = () => {\n const list = this.imageList;\n if (list.length <= 1) return;\n this.current = (this.currentIndex - 1 + list.length) % list.length;\n this.emitChange();\n };\n\n private zoomIn = () => {\n const next = Math.min(this.zoom + this.zoomStep, this.maxZoom);\n this.zoom = Math.round(next * 100) / 100;\n };\n\n private zoomOut = () => {\n const next = Math.max(this.zoom - this.zoomStep, this.minZoom);\n this.zoom = Math.round(next * 100) / 100;\n };\n\n private handleReset = () => {\n this.zoom = 1;\n this.rotate = 0;\n };\n\n private handleRotateLeft = () => {\n this.rotate = this.rotate - 90;\n };\n\n private handleRotateRight = () => {\n this.rotate = this.rotate + 90;\n };\n\n /**\n * 滚轮缩放(平滑 + 像素级响应):\n * 按 deltaY 的绝对值映射缩放因子(小滚幅小步、大滚幅大步),\n * 并夹取到 [minZoom, maxZoom],避免抖动与越界。\n */\n private handleWheel = (e: WheelEvent) => {\n e.preventDefault();\n // 把 deltaY 映射成指数缩放系数:wheel 越快缩放越激进,但单次不超 zoomStep*2\n const dir = e.deltaY < 0 ? 1 : -1;\n const intensity = Math.min(Math.abs(e.deltaY) / 100, 2); // 0~2\n const factor = 1 + dir * this.zoomStep * Math.max(1, intensity);\n const next = Math.max(this.minZoom, Math.min(this.zoom * factor, this.maxZoom));\n // 平滑:小数位保留两位,避免浮点累积误差\n this.zoom = Math.round(next * 100) / 100;\n };\n\n /** 点击遮罩空白处关闭 */\n private handleOverlayClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget) {\n this.close();\n }\n };\n\n private stopAndClose = (e: MouseEvent) => {\n e.stopPropagation();\n this.close();\n };\n\n render() {\n if (!this.modelValue) return null;\n\n const imgStyle = {\n transform: `scale(${this.zoom}) rotate(${this.rotate}deg)`,\n };\n\n return (\n <div class=\"hb-image-preview\" onClick={this.handleOverlayClick}>\n <div class=\"hb-image-preview__wrapper\">\n <img\n class=\"hb-image-preview__img\"\n src={this.currentSrc}\n alt=\"\"\n style={imgStyle}\n onWheel={this.handleWheel}\n />\n </div>\n\n {this.isMulti && (\n <button\n type=\"button\"\n class=\"hb-image-preview__btn hb-image-preview__btn--prev\"\n onClick={this.prev}\n aria-label=\"上一张\"\n >\n ‹\n </button>\n )}\n {this.isMulti && (\n <button\n type=\"button\"\n class=\"hb-image-preview__btn hb-image-preview__btn--next\"\n onClick={this.next}\n aria-label=\"下一张\"\n >\n ›\n </button>\n )}\n\n <div class=\"hb-image-preview__toolbar\" onClick={(e) => e.stopPropagation()}>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.zoomOut} aria-label=\"缩小\">\n -\n </button>\n <span class=\"hb-image-preview__tool-label\">{Math.round(this.zoom * 100)}%</span>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.zoomIn} aria-label=\"放大\">\n +\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.handleRotateLeft} aria-label=\"左旋\">\n ↺\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.handleRotateRight} aria-label=\"右旋\">\n ↻\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.handleReset} aria-label=\"重置\">\n ⟲\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.stopAndClose} aria-label=\"关闭\">\n ✕\n </button>\n </div>\n\n <button\n type=\"button\"\n class=\"hb-image-preview__close\"\n onClick={this.stopAndClose}\n aria-label=\"关闭\"\n >\n ×\n </button>\n </div>\n );\n }\n}\n"],"version":3}
|
|
1
|
+
{"file":"hb-image-preview.entry.cjs.js","mappings":"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","names":["h"],"sources":["src/components/ImagePreview/image-preview.css?tag=hb-image-preview&encapsulation=shadow","src/components/ImagePreview/ImagePreview.tsx"],"sourcesContent":[":host {\n display: contents;\n}\n\n.hb-image-preview {\n position: fixed;\n inset: 0;\n z-index: var(--hb-z-index-modal-mask, 2000);\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--hb-color-bg-mask, rgba(0, 0, 0, 0.5));\n}\n\n.hb-image-preview__wrapper {\n max-width: 90vw;\n max-height: 90vh;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.hb-image-preview__img {\n max-width: 90vw;\n max-height: 90vh;\n object-fit: contain;\n user-select: none;\n transition: transform 0.2s ease;\n pointer-events: none;\n}\n\n.hb-image-preview__btn {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background-color: rgba(0, 0, 0, 0.4);\n color: var(--hb-color-text-inverse, #ffffff);\n font-size: 28px;\n line-height: 1;\n cursor: pointer;\n transition: background-color var(--hb-transition-duration, 0.2s) ease;\n}\n\n.hb-image-preview__btn:hover {\n background-color: rgba(0, 0, 0, 0.6);\n}\n\n.hb-image-preview__btn--prev {\n left: 24px;\n}\n\n.hb-image-preview__btn--next {\n right: 24px;\n}\n\n.hb-image-preview__toolbar {\n position: absolute;\n bottom: 32px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 12px;\n border-radius: var(--hb-border-radius-base, 4px);\n background-color: rgba(0, 0, 0, 0.5);\n color: var(--hb-color-text-inverse, #ffffff);\n}\n\n.hb-image-preview__tool {\n min-width: 32px;\n height: 32px;\n padding: 0 8px;\n border: none;\n border-radius: var(--hb-border-radius-sm, 2px);\n background: transparent;\n color: var(--hb-color-text-inverse, #ffffff);\n font-size: 16px;\n cursor: pointer;\n transition: background-color var(--hb-transition-duration, 0.2s) ease;\n}\n\n.hb-image-preview__tool:hover {\n background-color: rgba(255, 255, 255, 0.15);\n}\n\n.hb-image-preview__tool-label {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 48px;\n padding: 0 4px;\n font-size: 13px;\n color: var(--hb-color-text-inverse, #ffffff);\n}\n\n.hb-image-preview__close {\n position: absolute;\n top: 24px;\n right: 24px;\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background-color: rgba(0, 0, 0, 0.4);\n color: var(--hb-color-text-inverse, #ffffff);\n font-size: 28px;\n line-height: 1;\n cursor: pointer;\n transition: background-color var(--hb-transition-duration, 0.2s) ease;\n}\n\n.hb-image-preview__close:hover {\n background-color: rgba(0, 0, 0, 0.6);\n}\n","import { Component, h, Prop, Event, EventEmitter, State, Watch, Element } from '@stencil/core';\n\nexport interface ImagePreviewChangeDetail {\n src: string;\n index: number;\n}\n\n/**\n * ImagePreview 图片预览组件\n * 点击图片后展示大图,支持缩放、旋转、多图切换\n */\n@Component({\n tag: 'hb-image-preview',\n styleUrl: 'image-preview.css',\n shadow: true,\n})\nexport class ImagePreview {\n @Element() el: HTMLElement;\n\n /** 是否显示预览(受控,可双向) */\n @Prop({ mutable: true }) modelValue: boolean = false;\n\n /** 单图源(srcList 为空时使用) */\n @Prop() src: string = '';\n\n /** 多图源列表 */\n @Prop() srcList: string[] = [];\n\n /** 多图当前索引 */\n @Prop({ mutable: true }) current: number = 0;\n\n /** 单次缩放步长 */\n @Prop() zoomStep: number = 0.2;\n\n /** 最小缩放比例 */\n @Prop() minZoom: number = 0.5;\n\n /** 最大缩放比例 */\n @Prop() maxZoom: number = 3;\n\n /** 关闭事件 */\n @Event() hbClose: EventEmitter<void>;\n\n /** 切换事件,detail 为 { src, index } */\n @Event() hbChange: EventEmitter<ImagePreviewChangeDetail>;\n\n /** 当前缩放比例 */\n @State() zoom: number = 1;\n\n /** 当前旋转角度 */\n @State() rotate: number = 0;\n\n private keyDownHandler = (e: KeyboardEvent) => {\n if (!this.modelValue) return;\n if (e.key === 'Escape') {\n this.close();\n } else if (e.key === 'ArrowLeft') {\n this.prev();\n } else if (e.key === 'ArrowRight') {\n this.next();\n }\n };\n\n @Watch('modelValue')\n handleVisibleChange(newVal: boolean) {\n if (newVal) {\n // 打开时重置缩放与旋转\n this.zoom = 1;\n this.rotate = 0;\n document.addEventListener('keydown', this.keyDownHandler);\n } else {\n document.removeEventListener('keydown', this.keyDownHandler);\n }\n }\n\n @Watch('current')\n handleCurrentChange() {\n // 切换图片时重置变换\n this.zoom = 1;\n this.rotate = 0;\n }\n\n componentDidLoad() {\n if (this.modelValue) {\n document.addEventListener('keydown', this.keyDownHandler);\n }\n }\n\n disconnectedCallback() {\n document.removeEventListener('keydown', this.keyDownHandler);\n }\n\n /** 实际可切换的图片列表 */\n private get imageList(): string[] {\n if (this.srcList && this.srcList.length > 0) {\n return this.srcList;\n }\n return this.src ? [this.src] : [];\n }\n\n private get currentIndex(): number {\n const list = this.imageList;\n if (list.length === 0) return 0;\n if (this.current < 0) return 0;\n if (this.current >= list.length) return list.length - 1;\n return this.current;\n }\n\n private get currentSrc(): string {\n const list = this.imageList;\n if (list.length === 0) return '';\n return list[this.currentIndex] || '';\n }\n\n private get isMulti(): boolean {\n return this.imageList.length > 1;\n }\n\n private close = () => {\n this.modelValue = false;\n this.hbClose.emit();\n };\n\n private emitChange() {\n this.hbChange.emit({ src: this.currentSrc, index: this.currentIndex });\n }\n\n private next = () => {\n const list = this.imageList;\n if (list.length <= 1) return;\n this.current = (this.currentIndex + 1) % list.length;\n this.emitChange();\n };\n\n private prev = () => {\n const list = this.imageList;\n if (list.length <= 1) return;\n this.current = (this.currentIndex - 1 + list.length) % list.length;\n this.emitChange();\n };\n\n private zoomIn = () => {\n const next = Math.min(this.zoom + this.zoomStep, this.maxZoom);\n this.zoom = Math.round(next * 100) / 100;\n };\n\n private zoomOut = () => {\n const next = Math.max(this.zoom - this.zoomStep, this.minZoom);\n this.zoom = Math.round(next * 100) / 100;\n };\n\n private handleReset = () => {\n this.zoom = 1;\n this.rotate = 0;\n };\n\n private handleRotateLeft = () => {\n this.rotate = this.rotate - 90;\n };\n\n private handleRotateRight = () => {\n this.rotate = this.rotate + 90;\n };\n\n /**\n * 滚轮缩放(平滑 + 像素级响应):\n * 按 deltaY 的绝对值映射缩放因子(小滚幅小步、大滚幅大步),\n * 并夹取到 [minZoom, maxZoom],避免抖动与越界。\n */\n private handleWheel = (e: WheelEvent) => {\n e.preventDefault();\n // 把 deltaY 映射成指数缩放系数:wheel 越快缩放越激进,但单次不超 zoomStep*2\n const dir = e.deltaY < 0 ? 1 : -1;\n const intensity = Math.min(Math.abs(e.deltaY) / 100, 2); // 0~2\n const factor = 1 + dir * this.zoomStep * Math.max(1, intensity);\n const next = Math.max(this.minZoom, Math.min(this.zoom * factor, this.maxZoom));\n // 平滑:小数位保留两位,避免浮点累积误差\n this.zoom = Math.round(next * 100) / 100;\n };\n\n /** 点击遮罩空白处关闭 */\n private handleOverlayClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget) {\n this.close();\n }\n };\n\n private stopAndClose = (e: MouseEvent) => {\n e.stopPropagation();\n this.close();\n };\n\n render() {\n if (!this.modelValue) return null;\n\n const imgStyle = {\n transform: `scale(${this.zoom}) rotate(${this.rotate}deg)`,\n };\n\n return (\n <div class=\"hb-image-preview\" onClick={this.handleOverlayClick}>\n <div class=\"hb-image-preview__wrapper\">\n <img class=\"hb-image-preview__img\" src={this.currentSrc} alt=\"\" style={imgStyle} onWheel={this.handleWheel} />\n </div>\n\n {this.isMulti && (\n <button type=\"button\" class=\"hb-image-preview__btn hb-image-preview__btn--prev\" onClick={this.prev} aria-label=\"上一张\">\n ‹\n </button>\n )}\n {this.isMulti && (\n <button type=\"button\" class=\"hb-image-preview__btn hb-image-preview__btn--next\" onClick={this.next} aria-label=\"下一张\">\n ›\n </button>\n )}\n\n <div class=\"hb-image-preview__toolbar\" onClick={e => e.stopPropagation()}>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.zoomOut} aria-label=\"缩小\">\n -\n </button>\n <span class=\"hb-image-preview__tool-label\">{Math.round(this.zoom * 100)}%</span>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.zoomIn} aria-label=\"放大\">\n +\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.handleRotateLeft} aria-label=\"左旋\">\n ↺\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.handleRotateRight} aria-label=\"右旋\">\n ↻\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.handleReset} aria-label=\"重置\">\n ⟲\n </button>\n <button type=\"button\" class=\"hb-image-preview__tool\" onClick={this.stopAndClose} aria-label=\"关闭\">\n ✕\n </button>\n </div>\n\n <button type=\"button\" class=\"hb-image-preview__close\" onClick={this.stopAndClose} aria-label=\"关闭\">\n ×\n </button>\n </div>\n );\n }\n}\n"],"version":3}
|