@multiplatform.one/forms 7.68.0 → 7.69.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/AdaptivePopup/index.native.js +2 -2
- package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
- package/dist/cjs/Button/IconButtonGroup.cjs +95 -0
- package/dist/cjs/Button/IconButtonGroup.native.js +101 -0
- package/dist/cjs/Button/IconButtonGroup.native.js.map +1 -0
- package/dist/cjs/Button/glass.cjs +4 -0
- package/dist/cjs/Button/glass.native.js +8 -0
- package/dist/cjs/Button/glass.native.js.map +1 -1
- package/dist/cjs/Button/iconButtonGroupContext.cjs +33 -0
- package/dist/cjs/Button/iconButtonGroupContext.native.js +36 -0
- package/dist/cjs/Button/iconButtonGroupContext.native.js.map +1 -0
- package/dist/cjs/Button/index.cjs +35 -20
- package/dist/cjs/Button/index.native.js +38 -22
- package/dist/cjs/Button/index.native.js.map +1 -1
- package/dist/cjs/Button/mediaPlate.cjs +31 -0
- package/dist/cjs/Button/mediaPlate.native.js +34 -0
- package/dist/cjs/Button/mediaPlate.native.js.map +1 -0
- package/dist/cjs/Chip/index.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js +1 -1
- package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/index.native.js +3 -3
- package/dist/cjs/ContextualSaveBar/index.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
- package/dist/cjs/ControlGroup/index.native.js +1 -1
- package/dist/cjs/ControlGroup/index.native.js.map +1 -1
- package/dist/cjs/DescriptionList/index.native.js +2 -2
- package/dist/cjs/DescriptionList/index.native.js.map +1 -1
- package/dist/cjs/ErrorSummary.native.js.map +1 -1
- package/dist/cjs/FieldDisplay/editMode.native.js.map +1 -1
- package/dist/cjs/FieldDisplay/formatters.native.js.map +1 -1
- package/dist/cjs/FieldDisplay/index.native.js +1 -1
- package/dist/cjs/FieldDisplay/index.native.js.map +1 -1
- package/dist/cjs/FieldGroup.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/RegularPanel.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/compactFace.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/containingBlock.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/index.native.js +21 -16
- package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/nestedAction.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/regularPlacement.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/trailingAction.native.js +1 -1
- package/dist/cjs/FloatingPanel/trailingAction.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/useFloatingPanel.native.js.map +1 -1
- package/dist/cjs/Form/index.native.js +1 -1
- package/dist/cjs/Form/index.native.js.map +1 -1
- package/dist/cjs/Form/submissionController.native.js.map +1 -1
- package/dist/cjs/Form/validateOn.native.js.map +1 -1
- package/dist/cjs/FormGrid.native.js.map +1 -1
- package/dist/cjs/FormSection.native.js.map +1 -1
- package/dist/cjs/InputParts/PasswordReveal.native.js.map +1 -1
- package/dist/cjs/InputParts/index.native.js.map +1 -1
- package/dist/cjs/Label/index.native.js.map +1 -1
- package/dist/cjs/MediaPicker/base64.native.js.map +1 -1
- package/dist/cjs/MediaPicker/payload.native.js.map +1 -1
- package/dist/cjs/MediaPicker/types.native.js.map +1 -1
- package/dist/cjs/MediaPicker/useMediaPicker.native.js.map +1 -1
- package/dist/cjs/Skeleton/index.native.js.map +1 -1
- package/dist/cjs/Spinner/SpinnerGlyph.native.js.map +1 -1
- package/dist/cjs/Spinner/spinnerSize.native.js.map +1 -1
- package/dist/cjs/Table/index.native.js.map +1 -1
- package/dist/cjs/Wheel/haptic.native.js.map +1 -1
- package/dist/cjs/Wheel/index.native.js.map +1 -1
- package/dist/cjs/Wheel/wheelShared.native.js.map +1 -1
- package/dist/cjs/actionLabel.native.js.map +1 -1
- package/dist/cjs/fieldDefaults.native.js.map +1 -1
- package/dist/cjs/fieldLayout.native.js +1 -1
- package/dist/cjs/fieldLayout.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/BarcodePreview.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/BarcodeScanner.native.js +1 -1
- package/dist/cjs/fields/Barcode/code128.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/index.native.js +2 -2
- package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/qr.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/scannerTypes.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/Checkbox.native.js +1 -1
- package/dist/cjs/fields/Checkbox/Checkbox.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxBox.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxCard.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js +1 -1
- package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
- package/dist/cjs/fields/Checkbox/index.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/SystemColorField.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/index.native.js +2 -2
- package/dist/cjs/fields/ColorPicker/index.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/parts.native.js +2 -2
- package/dist/cjs/fields/ColorPicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/ColorPicker/systemColorWell.gnome.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/authorOptions.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/index.native.js +5 -5
- package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +3 -3
- package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/MonthPicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +2 -2
- package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/catalog.native.js +2 -2
- package/dist/cjs/fields/DatePicker/catalog.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/fieldValueSync.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/index.native.js +2 -2
- package/dist/cjs/fields/DatePicker/parts.native.js +2 -2
- package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/utils.native.js.map +1 -1
- package/dist/cjs/fields/Duration/durationMath.native.js.map +1 -1
- package/dist/cjs/fields/Duration/index.native.js +3 -3
- package/dist/cjs/fields/Duration/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/filePickerTypes.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/index.cjs +4 -1
- package/dist/cjs/fields/FileUpload/index.native.js +6 -3
- package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/geoValue.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/geocoder.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/geocoderContext.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/index.native.js +5 -5
- package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/mapMath.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/mapTypes.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/photonGeocoder.native.js.map +1 -1
- package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
- package/dist/cjs/fields/Icon/index.native.js +3 -3
- package/dist/cjs/fields/Icon/index.native.js.map +1 -1
- package/dist/cjs/fields/ImageField/index.native.js +2 -2
- package/dist/cjs/fields/ImageField/index.native.js.map +1 -1
- package/dist/cjs/fields/Input/index.native.js +3 -3
- package/dist/cjs/fields/Input/index.native.js.map +1 -1
- package/dist/cjs/fields/MentionInput/index.native.js +3 -3
- package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
- package/dist/cjs/fields/OTPInput/index.native.js +3 -3
- package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
- package/dist/cjs/fields/OTPInput/otpCellCss.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/dialCodes.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/index.native.js +3 -3
- package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/phone.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/regionNames.native.js.map +1 -1
- package/dist/cjs/fields/Progress/index.native.js +1 -1
- package/dist/cjs/fields/Progress/index.native.js.map +1 -1
- package/dist/cjs/fields/RadioGroup/index.native.js +1 -1
- package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/Rating/index.native.js +1 -1
- package/dist/cjs/fields/Rating/index.native.js.map +1 -1
- package/dist/cjs/fields/Rating/ratingMath.native.js.map +1 -1
- package/dist/cjs/fields/Rating/types.native.js.map +1 -1
- package/dist/cjs/fields/SearchInput/index.native.js +2 -2
- package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/Select/SheetPickerRow.native.js.map +1 -1
- package/dist/cjs/fields/Select/index.native.js +4 -4
- package/dist/cjs/fields/Select/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/Signature/index.native.js +2 -2
- package/dist/cjs/fields/Signature/index.native.js.map +1 -1
- package/dist/cjs/fields/Slider/index.native.js +1 -1
- package/dist/cjs/fields/Slider/index.native.js.map +1 -1
- package/dist/cjs/fields/Slider/jumpMotion.native.js.map +1 -1
- package/dist/cjs/fields/Stepper/index.native.js +2 -2
- package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
- package/dist/cjs/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
- package/dist/cjs/fields/Switch/footprint.native.js.map +1 -1
- package/dist/cjs/fields/Switch/index.native.js +2 -2
- package/dist/cjs/fields/Switch/index.native.js.map +1 -1
- package/dist/cjs/fields/TextArea/index.native.js +2 -2
- package/dist/cjs/fields/TextArea/index.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/catalog.native.js +3 -3
- package/dist/cjs/fields/TimePicker/catalog.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/index.native.js +2 -2
- package/dist/cjs/fields/TimePicker/parts.native.js +1 -1
- package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
- package/dist/cjs/fields/TimeRangeScrubber/index.native.js +2 -2
- package/dist/cjs/fields/TimeRangeScrubber/index.native.js.map +1 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js +1 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +1 -1
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -1
- package/dist/cjs/fields/nativeSelect.native.js.map +1 -1
- package/dist/cjs/fields/selectedOrder.native.js.map +1 -1
- package/dist/cjs/formSpacing.native.js.map +1 -1
- package/dist/cjs/hooks/useFocusManagement.native.js.map +1 -1
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/index.native.js +48 -45
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/keyboard/KeyboardDoneBar.native.js +1 -1
- package/dist/cjs/keyboard/chain.native.js.map +1 -1
- package/dist/cjs/keyboard/index.native.js.map +1 -1
- package/dist/cjs/keyboard/types.native.js.map +1 -1
- package/dist/cjs/requiredMarking.native.js.map +1 -1
- package/dist/cjs/shared/TimeColumn.native.js +1 -1
- package/dist/cjs/shared/TimeColumn.native.js.map +1 -1
- package/dist/cjs/shared/capabilityPreflight.native.js.map +1 -1
- package/dist/cjs/shared/choiceRowPress.native.js.map +1 -1
- package/dist/cjs/shared/colorRamps.native.js.map +1 -1
- package/dist/cjs/shared/devWarn.native.js.map +1 -1
- package/dist/cjs/shared/floatingList.native.js +1 -1
- package/dist/cjs/shared/floatingList.native.js.map +1 -1
- package/dist/cjs/shared/focusManagement.native.js.map +1 -1
- package/dist/cjs/shared/groupContext.native.js.map +1 -1
- package/dist/cjs/shared/i18n.native.js.map +1 -1
- package/dist/cjs/shared/instantMotion.native.js.map +1 -1
- package/dist/cjs/shared/nativeA11y.native.js.map +1 -1
- package/dist/cjs/shared/nativeAutoFocus.native.js.map +1 -1
- package/dist/cjs/shared/overlaySizeClass.native.js.map +1 -1
- package/dist/cjs/shared/overlayStack.native.js.map +1 -1
- package/dist/cjs/shared/panelPortal.native.js.map +1 -1
- package/dist/cjs/shared/pickerTriggerContract.native.js.map +1 -1
- package/dist/cjs/shared/pressSlopProps.native.js.map +1 -1
- package/dist/cjs/shared/restoreRetries.native.js.map +1 -1
- package/dist/cjs/shared/sheetNavigation.native.js.map +1 -1
- package/dist/cjs/shared/systemControlModules.gnome.native.js.map +1 -1
- package/dist/cjs/shared/systemControls.native.js.map +1 -1
- package/dist/cjs/shared/t.native.js.map +1 -1
- package/dist/cjs/shared/tableCellContext.native.js.map +1 -1
- package/dist/cjs/shared/touchWebPicker.native.js.map +1 -1
- package/dist/cjs/shared/useDragScroll.native.js.map +1 -1
- package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/cjs/shared/useSheetEscapeDismiss.native.js.map +1 -1
- package/dist/cjs/shared/useWheelIncrement.native.js.map +1 -1
- package/dist/cjs/shared/utils.native.js +1 -1
- package/dist/cjs/shared/utils.native.js.map +1 -1
- package/dist/cjs/shared/zIndex.native.js.map +1 -1
- package/dist/cjs/standardActions.native.js.map +1 -1
- package/dist/cjs/themedPrimitives.native.js.map +1 -1
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/cjs/utils/LinkCell.native.js.map +1 -1
- package/dist/esm/Button/IconButtonGroup.mjs +69 -0
- package/dist/esm/Button/IconButtonGroup.mjs.map +1 -0
- package/dist/esm/Button/IconButtonGroup.native.js +72 -0
- package/dist/esm/Button/IconButtonGroup.native.js.map +1 -0
- package/dist/esm/Button/glass.mjs +4 -1
- package/dist/esm/Button/glass.mjs.map +1 -1
- package/dist/esm/Button/glass.native.js +8 -1
- package/dist/esm/Button/glass.native.js.map +1 -1
- package/dist/esm/Button/iconButtonGroupContext.mjs +7 -0
- package/dist/esm/Button/iconButtonGroupContext.mjs.map +1 -0
- package/dist/esm/Button/iconButtonGroupContext.native.js +7 -0
- package/dist/esm/Button/iconButtonGroupContext.native.js.map +1 -0
- package/dist/esm/Button/index.mjs +32 -21
- package/dist/esm/Button/index.mjs.map +1 -1
- package/dist/esm/Button/index.native.js +33 -21
- package/dist/esm/Button/index.native.js.map +1 -1
- package/dist/esm/Button/mediaPlate.mjs +6 -0
- package/dist/esm/Button/mediaPlate.mjs.map +1 -0
- package/dist/esm/Button/mediaPlate.native.js +6 -0
- package/dist/esm/Button/mediaPlate.native.js.map +1 -0
- package/dist/esm/FloatingPanel/index.native.js +22 -17
- package/dist/esm/FloatingPanel/index.native.js.map +1 -1
- package/dist/esm/fields/FileUpload/index.mjs +5 -2
- package/dist/esm/fields/FileUpload/index.mjs.map +1 -1
- package/dist/esm/fields/FileUpload/index.native.js +5 -2
- package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +2 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/jsx/Button/IconButtonGroup.mjs +69 -0
- package/dist/jsx/Button/IconButtonGroup.mjs.map +1 -0
- package/dist/jsx/Button/IconButtonGroup.native.js +101 -0
- package/dist/jsx/Button/IconButtonGroup.native.js.map +1 -0
- package/dist/jsx/Button/glass.mjs +4 -1
- package/dist/jsx/Button/glass.mjs.map +1 -1
- package/dist/jsx/Button/glass.native.js +8 -0
- package/dist/jsx/Button/glass.native.js.map +1 -1
- package/dist/jsx/Button/iconButtonGroupContext.mjs +7 -0
- package/dist/jsx/Button/iconButtonGroupContext.mjs.map +1 -0
- package/dist/jsx/Button/iconButtonGroupContext.native.js +36 -0
- package/dist/jsx/Button/iconButtonGroupContext.native.js.map +1 -0
- package/dist/jsx/Button/index.mjs +32 -21
- package/dist/jsx/Button/index.mjs.map +1 -1
- package/dist/jsx/Button/index.native.js +36 -20
- package/dist/jsx/Button/index.native.js.map +1 -1
- package/dist/jsx/Button/mediaPlate.mjs +6 -0
- package/dist/jsx/Button/mediaPlate.mjs.map +1 -0
- package/dist/jsx/Button/mediaPlate.native.js +34 -0
- package/dist/jsx/Button/mediaPlate.native.js.map +1 -0
- package/dist/jsx/FloatingPanel/index.native.js +21 -16
- package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
- package/dist/jsx/fields/FileUpload/index.mjs +5 -2
- package/dist/jsx/fields/FileUpload/index.mjs.map +1 -1
- package/dist/jsx/fields/FileUpload/index.native.js +4 -1
- package/dist/jsx/fields/FileUpload/index.native.js.map +1 -1
- package/dist/jsx/index.js +2 -2
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +2 -2
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +3 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/package.json +8 -8
- package/src/Button/Button.iconButton.spec.tsx +76 -14
- package/src/Button/Button.stories.tsx +142 -21
- package/src/Button/IconButtonGroup.spec.tsx +126 -0
- package/src/Button/IconButtonGroup.tsx +87 -0
- package/src/Button/glass.native.ts +15 -2
- package/src/Button/glass.ts +16 -1
- package/src/Button/iconButtonGroupContext.ts +14 -0
- package/src/Button/index.tsx +82 -42
- package/src/Button/mediaPlate.ts +9 -0
- package/src/FloatingPanel/FloatingPanel.pointMenu.native.spec.tsx +69 -0
- package/src/FloatingPanel/index.native.tsx +25 -4
- package/src/fields/FileUpload/FileUpload.spec.tsx +11 -7
- package/src/fields/FileUpload/index.tsx +4 -2
- package/src/index.ts +9 -1
- package/types/Button/IconButtonGroup.d.ts +22 -0
- package/types/Button/IconButtonGroup.d.ts.map +1 -0
- package/types/Button/glass.d.ts +12 -1
- package/types/Button/glass.d.ts.map +1 -1
- package/types/Button/glass.native.d.ts +8 -2
- package/types/Button/glass.native.d.ts.map +1 -1
- package/types/Button/iconButtonGroupContext.d.ts +9 -0
- package/types/Button/iconButtonGroupContext.d.ts.map +1 -0
- package/types/Button/index.d.ts +18 -9
- package/types/Button/index.d.ts.map +1 -1
- package/types/Button/mediaPlate.d.ts +10 -0
- package/types/Button/mediaPlate.d.ts.map +1 -0
- package/types/FloatingPanel/index.native.d.ts +2 -1
- package/types/FloatingPanel/index.native.d.ts.map +1 -1
- package/types/fields/FileUpload/index.d.ts.map +1 -1
- package/types/index.d.ts +2 -2
- package/types/index.d.ts.map +1 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { radiusClassProps, useBarSurface } from "@multiplatform.one/theme";
|
|
2
|
+
import { useState, type ReactNode } from "react";
|
|
3
|
+
import { isWeb, Theme, View, XStack, type XStackProps } from "tamagui";
|
|
4
|
+
import { loadGlassView } from "./glass";
|
|
5
|
+
import { MEDIA_PLATE_WEB_STYLE } from "./mediaPlate";
|
|
6
|
+
import { IconButtonGroupContext } from "./iconButtonGroupContext";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* LC-176: how far apart two Liquid Glass circles may sit and still merge. Half
|
|
10
|
+
* the 44pt target, so neighbours on the bar's gap always join.
|
|
11
|
+
*/
|
|
12
|
+
export const ICON_BUTTON_GLASS_MERGE_PX = 22;
|
|
13
|
+
|
|
14
|
+
export interface IconButtonGroupProps extends XStackProps {
|
|
15
|
+
/** Over imagery or video: the group shares one material capsule. */
|
|
16
|
+
plate?: "media";
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* LC-176: icon buttons that sit side by side. Grounds merge, they never stand
|
|
22
|
+
* as a row of separate circles: on iOS 26 the bar's group is one Liquid Glass
|
|
23
|
+
* capsule, as the system draws a bar's item group (merging each circle through
|
|
24
|
+
* the glass container left a waist between them, FZ-8158); over media the
|
|
25
|
+
* group shares one material capsule; a bare row stays bare. A lone button
|
|
26
|
+
* keeps its own circle.
|
|
27
|
+
*/
|
|
28
|
+
export function IconButtonGroup({ plate, children, ...rest }: IconButtonGroupProps) {
|
|
29
|
+
const bar = useBarSurface();
|
|
30
|
+
const [capsuleHeight, setCapsuleHeight] = useState(0);
|
|
31
|
+
if (plate === "media") {
|
|
32
|
+
return (
|
|
33
|
+
<IconButtonGroupContext.Provider value="media">
|
|
34
|
+
<Theme name="dark">
|
|
35
|
+
<XStack
|
|
36
|
+
alignItems="center"
|
|
37
|
+
alignSelf="flex-start"
|
|
38
|
+
borderRadius={100000}
|
|
39
|
+
backgroundColor="$shadow4"
|
|
40
|
+
overflow="hidden"
|
|
41
|
+
data-mp-icon-button-group="media"
|
|
42
|
+
{...radiusClassProps("R-IDENTITY", "icon button plate")}
|
|
43
|
+
{...(isWeb ? { style: MEDIA_PLATE_WEB_STYLE } : undefined)}
|
|
44
|
+
{...rest}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
</XStack>
|
|
48
|
+
</Theme>
|
|
49
|
+
</IconButtonGroupContext.Provider>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const GlassView = bar ? loadGlassView() : null;
|
|
53
|
+
const row = (
|
|
54
|
+
<XStack
|
|
55
|
+
alignItems="center"
|
|
56
|
+
data-mp-icon-button-group={GlassView ? "glass" : bar ? "bar" : "row"}
|
|
57
|
+
{...rest}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
</XStack>
|
|
61
|
+
);
|
|
62
|
+
if (!GlassView) return row;
|
|
63
|
+
return (
|
|
64
|
+
<IconButtonGroupContext.Provider value="glass">
|
|
65
|
+
<View
|
|
66
|
+
position="relative"
|
|
67
|
+
flexShrink={1}
|
|
68
|
+
minWidth={0}
|
|
69
|
+
onLayout={(event) => setCapsuleHeight(event.nativeEvent.layout.height)}
|
|
70
|
+
>
|
|
71
|
+
<GlassView
|
|
72
|
+
glassEffectStyle="regular"
|
|
73
|
+
pointerEvents="none"
|
|
74
|
+
style={{
|
|
75
|
+
position: "absolute",
|
|
76
|
+
top: 0,
|
|
77
|
+
right: 0,
|
|
78
|
+
bottom: 0,
|
|
79
|
+
left: 0,
|
|
80
|
+
borderRadius: capsuleHeight / 2,
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
{row}
|
|
84
|
+
</View>
|
|
85
|
+
</IconButtonGroupContext.Provider>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { GlassViewComponent } from "./glass";
|
|
1
|
+
import type { GlassContainerComponent, GlassViewComponent } from "./glass";
|
|
2
2
|
|
|
3
|
-
export type { GlassViewComponent } from "./glass";
|
|
3
|
+
export type { GlassContainerComponent, GlassViewComponent } from "./glass";
|
|
4
4
|
|
|
5
5
|
let cachedGlassView: GlassViewComponent | null | undefined;
|
|
6
|
+
let cachedGlassContainer: GlassContainerComponent | null | undefined;
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* LC-176: expo-glass-effect's `GlassView`, when this binary links its native
|
|
@@ -21,6 +22,7 @@ export function loadGlassView(): GlassViewComponent | null {
|
|
|
21
22
|
if (core.requireOptionalNativeModule?.("ExpoGlassEffect") == null) return cachedGlassView;
|
|
22
23
|
const glass = require("expo-glass-effect") as {
|
|
23
24
|
GlassView?: GlassViewComponent;
|
|
25
|
+
GlassContainer?: GlassContainerComponent;
|
|
24
26
|
isLiquidGlassAvailable?: () => boolean;
|
|
25
27
|
isGlassEffectAPIAvailable?: () => boolean;
|
|
26
28
|
};
|
|
@@ -30,9 +32,20 @@ export function loadGlassView(): GlassViewComponent | null {
|
|
|
30
32
|
glass.isGlassEffectAPIAvailable?.()
|
|
31
33
|
) {
|
|
32
34
|
cachedGlassView = glass.GlassView;
|
|
35
|
+
cachedGlassContainer = glass.GlassContainer ?? null;
|
|
33
36
|
}
|
|
34
37
|
} catch {
|
|
35
38
|
cachedGlassView = null;
|
|
36
39
|
}
|
|
37
40
|
return cachedGlassView;
|
|
38
41
|
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* LC-176: expo-glass-effect's `GlassContainer`, present exactly when
|
|
45
|
+
* `loadGlassView` found Liquid Glass. A binary whose module predates the
|
|
46
|
+
* container keeps separate circles rather than throwing.
|
|
47
|
+
*/
|
|
48
|
+
export function loadGlassContainer(): GlassContainerComponent | null {
|
|
49
|
+
if (cachedGlassView === undefined) loadGlassView();
|
|
50
|
+
return cachedGlassContainer ?? null;
|
|
51
|
+
}
|
package/src/Button/glass.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ComponentType } from "react";
|
|
1
|
+
import type { ComponentType, ReactNode } from "react";
|
|
2
2
|
|
|
3
3
|
/** The slice of expo-glass-effect's `GlassView` an icon button draws. */
|
|
4
4
|
export type GlassViewComponent = ComponentType<{
|
|
@@ -8,6 +8,13 @@ export type GlassViewComponent = ComponentType<{
|
|
|
8
8
|
pointerEvents?: "none" | "auto" | "box-none" | "box-only";
|
|
9
9
|
}>;
|
|
10
10
|
|
|
11
|
+
/** The slice of expo-glass-effect's `GlassContainer` an icon button group draws. */
|
|
12
|
+
export type GlassContainerComponent = ComponentType<{
|
|
13
|
+
spacing?: number;
|
|
14
|
+
style?: unknown;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
11
18
|
/**
|
|
12
19
|
* LC-176: the iOS 26 Liquid Glass material an icon button floats on in a bar.
|
|
13
20
|
* Only iOS has it (`glass.native.ts`; the native module is Apple-only, so Android probes null); web, Android and GNOME draw the bare
|
|
@@ -16,3 +23,11 @@ export type GlassViewComponent = ComponentType<{
|
|
|
16
23
|
export function loadGlassView(): GlassViewComponent | null {
|
|
17
24
|
return null;
|
|
18
25
|
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* LC-176: the container that merges neighbouring Liquid Glass circles into one
|
|
29
|
+
* shape, as iOS 26 groups bar buttons. Only iOS has it.
|
|
30
|
+
*/
|
|
31
|
+
export function loadGlassContainer(): GlassContainerComponent | null {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* LC-176: the ground an `IconButtonGroup` paints under its buttons. `media`
|
|
5
|
+
* is one shared material capsule and `glass` one shared Liquid Glass capsule,
|
|
6
|
+
* so a button inside draws its bare glyph instead of its own circle.
|
|
7
|
+
*/
|
|
8
|
+
export type IconButtonGroupGround = "media" | "glass" | null;
|
|
9
|
+
|
|
10
|
+
export const IconButtonGroupContext = createContext<IconButtonGroupGround>(null);
|
|
11
|
+
|
|
12
|
+
export function useIconButtonGroupGround(): IconButtonGroupGround {
|
|
13
|
+
return useContext(IconButtonGroupContext);
|
|
14
|
+
}
|
package/src/Button/index.tsx
CHANGED
|
@@ -73,6 +73,8 @@ import { formButtonColors, formCommonColors } from "../shared/colorRamps";
|
|
|
73
73
|
import { warnBareDisabled, warnPositiveTabIndex, warnSizeRecipeEscape } from "../shared/devWarn";
|
|
74
74
|
import { useControlGrouped } from "../shared/groupContext";
|
|
75
75
|
import { loadGlassView } from "./glass";
|
|
76
|
+
import { MEDIA_PLATE_WEB_STYLE } from "./mediaPlate";
|
|
77
|
+
import { useIconButtonGroupGround } from "./iconButtonGroupContext";
|
|
76
78
|
|
|
77
79
|
/**
|
|
78
80
|
* Coordinated size recipe (Polaris slim/medium/large, Primer s/m/l, Linear
|
|
@@ -409,17 +411,36 @@ export interface ButtonProps extends Omit<
|
|
|
409
411
|
export const ICON_BUTTON_PRESS_OPACITY = 0.35;
|
|
410
412
|
|
|
411
413
|
/**
|
|
412
|
-
* LC-176:
|
|
413
|
-
*
|
|
414
|
-
* label-icon size of a small control.
|
|
414
|
+
* LC-176: an icon button's glyph floor. The glyph itself is sized to its row
|
|
415
|
+
* (`iconButtonGlyphPx`), so it is never smaller than a 44pt target's glyph.
|
|
415
416
|
*/
|
|
416
|
-
export const ICON_BUTTON_GLYPH_PX =
|
|
417
|
+
export const ICON_BUTTON_GLYPH_PX = 24;
|
|
418
|
+
|
|
419
|
+
/** LC-176: the content glyph's floor; the same bold, row-sized glyph. */
|
|
420
|
+
export const ICON_BUTTON_NEUTRAL_GLYPH_PX = 24;
|
|
417
421
|
|
|
418
422
|
/**
|
|
419
|
-
*
|
|
420
|
-
*
|
|
423
|
+
* Phosphor draws a glyph's ink across about 208 of its 256 units, so a glyph
|
|
424
|
+
* whose ink is as tall as a text line is that line over this ratio.
|
|
421
425
|
*/
|
|
422
|
-
|
|
426
|
+
const PHOSPHOR_INK_RATIO = 208 / 256;
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* LC-176: an icon button's glyph is as tall in ink as the row's text line
|
|
430
|
+
* (YouTube's and the Phone app's bar glyphs), never a small glyph in a big
|
|
431
|
+
* target.
|
|
432
|
+
*/
|
|
433
|
+
export function iconButtonGlyphPx(rowLinePx: number | undefined): number {
|
|
434
|
+
if (rowLinePx === undefined) return ICON_BUTTON_GLYPH_PX;
|
|
435
|
+
return Math.max(ICON_BUTTON_GLYPH_PX, Math.round(rowLinePx / PHOSPHOR_INK_RATIO));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* LC-176: a glyph on a circle the caller asked for (`circular`, `outlined`)
|
|
440
|
+
* fills this share of the circle, the iOS Settings and Contacts leading-icon
|
|
441
|
+
* ratio, never a small glyph lost in a big plate.
|
|
442
|
+
*/
|
|
443
|
+
export const ICON_BUTTON_CIRCLE_GLYPH_RATIO = 0.58;
|
|
423
444
|
|
|
424
445
|
/** LC-176: an inline glyph is the text's size; Phosphor's 256 grid pads ~12%. */
|
|
425
446
|
const INLINE_GLYPH_RATIO = 1.2;
|
|
@@ -465,7 +486,7 @@ export function Button({
|
|
|
465
486
|
iconAfter,
|
|
466
487
|
selected,
|
|
467
488
|
nested = false,
|
|
468
|
-
circular,
|
|
489
|
+
circular: circularProp,
|
|
469
490
|
chromeless,
|
|
470
491
|
edge,
|
|
471
492
|
accentInk,
|
|
@@ -556,7 +577,12 @@ export function Button({
|
|
|
556
577
|
// (`outlined`, `circular`, `chromeless={false}`) or a segment owns it.
|
|
557
578
|
const labelled = verb != null || (children != null && children !== false && children !== "");
|
|
558
579
|
const iconOnly = !labelled && Boolean(icon || iconAfter);
|
|
559
|
-
|
|
580
|
+
// LC-176: `circular chromeless` paints no plate, so an icon-only one is an
|
|
581
|
+
// icon button like any other (the SHC console's add and copy buttons).
|
|
582
|
+
const circular = circularProp && !(iconOnly && chromeless === true && plate == null);
|
|
583
|
+
// LC-176: inside a group's shared capsule a button draws its glyph alone.
|
|
584
|
+
const groupGround = useIconButtonGroupGround();
|
|
585
|
+
const mediaPlate = iconOnly && plate === "media" && groupGround !== "media";
|
|
560
586
|
const confirmPlate = iconOnly && primaryPlate;
|
|
561
587
|
const iconButton =
|
|
562
588
|
iconOnly &&
|
|
@@ -575,12 +601,16 @@ export function Button({
|
|
|
575
601
|
// LC-176: the context picks the icon button's treatment, never the app. In a
|
|
576
602
|
// bar it takes the bar tint (the accent, on Liquid Glass where iOS draws
|
|
577
603
|
// it); in content, with no intent, it is a bold glyph in the text colour.
|
|
578
|
-
|
|
604
|
+
// An action inline with a value (copy beside an address) is tinted like a
|
|
605
|
+
// link, so it reads as the one pressable thing on the line.
|
|
606
|
+
const neutralGlyph =
|
|
607
|
+
iconButton && !(theme ?? intent) && !barSurface && accentInk == null && inline !== true;
|
|
579
608
|
if (iconButton) {
|
|
580
609
|
chromeless = true;
|
|
581
|
-
accentInk = accentInk ?? (!(theme ?? intent) && barSurface);
|
|
610
|
+
accentInk = accentInk ?? (!(theme ?? intent) && (barSurface || inline === true));
|
|
582
611
|
}
|
|
583
|
-
|
|
612
|
+
// LC-176: a glyph that is the whole button is bold, so it reads as one.
|
|
613
|
+
const resolvedGlyphWeight = glyphWeight ?? (iconOnly ? "bold" : "regular");
|
|
584
614
|
const elevatedGround = useElevatedSurface();
|
|
585
615
|
const darkScheme = isDarkThemeName(useThemeName());
|
|
586
616
|
const resolvedSize = typeof sizeProp === "number" ? sizeProp : knobProps.sizeToken;
|
|
@@ -773,34 +803,43 @@ export function Button({
|
|
|
773
803
|
const barGlyph =
|
|
774
804
|
((iconButton || mediaPlate || confirmPlate) && !nested) ||
|
|
775
805
|
(labelled && chromeless && accentInk === true && edge === "start");
|
|
776
|
-
const
|
|
777
|
-
|
|
806
|
+
const labelLine = labelLinePx(knobProps.body.fontFamily);
|
|
807
|
+
const glyphFloor = iconButtonGlyphPx(labelLine);
|
|
778
808
|
// LC-176: on iOS 26 a bar's icon button floats on Liquid Glass, the native
|
|
779
809
|
// bar button. Elsewhere, and on a binary without the module, it stays the
|
|
780
810
|
// bare tinted glyph.
|
|
811
|
+
const glassGroup = groupGround === "glass";
|
|
781
812
|
const GlassView =
|
|
782
|
-
iconButton && !inlineGlyph && !nested && accentInk && barSurface && !selectedFill
|
|
813
|
+
iconButton && !inlineGlyph && !nested && accentInk && barSurface && !selectedFill && !glassGroup
|
|
783
814
|
? loadGlassView()
|
|
784
815
|
: null;
|
|
816
|
+
const framedCircle = iconOnly && Boolean(circular) && !nested && !mediaPlate && !confirmPlate;
|
|
817
|
+
const framedCirclePx =
|
|
818
|
+
touch && typeof sizeProp !== "number"
|
|
819
|
+
? Math.max(sizeTokenPx(resolvedSize), MIN_PRESS_TARGET)
|
|
820
|
+
: sizeTokenPx(resolvedSize);
|
|
785
821
|
const iconSize = nested
|
|
786
822
|
? Math.min(recipe.iconSize, Math.max(12, Math.round(knobProps.nestedControl.px * 0.45)))
|
|
787
|
-
:
|
|
788
|
-
? Math.round(
|
|
789
|
-
:
|
|
790
|
-
?
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
823
|
+
: framedCircle
|
|
824
|
+
? Math.round(framedCirclePx * ICON_BUTTON_CIRCLE_GLYPH_RATIO)
|
|
825
|
+
: inlineGlyph
|
|
826
|
+
? Math.round(recipe.fontSize * INLINE_GLYPH_RATIO)
|
|
827
|
+
: barGlyph
|
|
828
|
+
? touch
|
|
829
|
+
? Math.max(glyphFloor, resolveButtonSizeRecipe("$6", recipeFamily, touch).iconSize)
|
|
830
|
+
: // A pointer toolbar keeps its token box (LC-54); the glyph fills it
|
|
831
|
+
// up to the same floor.
|
|
832
|
+
Math.max(recipe.iconSize, Math.min(glyphFloor, recipe.height - 8))
|
|
833
|
+
: recipe.iconSize;
|
|
796
834
|
const glyph =
|
|
797
|
-
barGlyph || inlineGlyph
|
|
835
|
+
barGlyph || inlineGlyph || framedCircle
|
|
836
|
+
? withGlyphWeight(icon, iconSize, resolvedGlyphWeight)
|
|
837
|
+
: icon;
|
|
798
838
|
|
|
799
839
|
// LC-158: the frame keeps its recipe height under Dynamic Type, so the
|
|
800
840
|
// label grows only as far as that height holds: its em and its line, which
|
|
801
841
|
// React Native scales by the same multiplier.
|
|
802
842
|
const labelBoxPx = nested ? knobProps.nestedControl.px : recipe.height;
|
|
803
|
-
const labelLine = labelLinePx(knobProps.body.fontFamily);
|
|
804
843
|
const labelMaxFontScale = Math.min(
|
|
805
844
|
maxFontScaleToFit(
|
|
806
845
|
labelBoxPx,
|
|
@@ -879,7 +918,7 @@ export function Button({
|
|
|
879
918
|
</View>
|
|
880
919
|
) : null;
|
|
881
920
|
const glyphAfter =
|
|
882
|
-
iconAfter && (barGlyph || inlineGlyph)
|
|
921
|
+
iconAfter && (barGlyph || inlineGlyph || framedCircle)
|
|
883
922
|
? withGlyphWeight(iconAfter, iconSize, resolvedGlyphWeight)
|
|
884
923
|
: iconAfter;
|
|
885
924
|
const iconAfterElement = glyphAfter ? (
|
|
@@ -994,11 +1033,8 @@ export function Button({
|
|
|
994
1033
|
: undefined;
|
|
995
1034
|
// A square box, so an `edge` pull puts the glyph itself on the gutter.
|
|
996
1035
|
// On glass the circle, not the glyph, sits on the margin.
|
|
997
|
-
const glyphEdgePull =
|
|
998
|
-
? 0
|
|
999
|
-
: iconButton
|
|
1000
|
-
? -Math.max(0, (visualPx - iconSize) / 2)
|
|
1001
|
-
: edgePull;
|
|
1036
|
+
const glyphEdgePull =
|
|
1037
|
+
GlassView || glassGroup ? 0 : iconButton ? -Math.max(0, (visualPx - iconSize) / 2) : edgePull;
|
|
1002
1038
|
const buttonElement = (
|
|
1003
1039
|
<ButtonFrame
|
|
1004
1040
|
// DG-ST-03: an explained disable is aria-disabled (focusable, press
|
|
@@ -1046,20 +1082,14 @@ export function Button({
|
|
|
1046
1082
|
? { width: visualPx, minWidth: visualPx, paddingHorizontal: 0 }
|
|
1047
1083
|
: undefined)}
|
|
1048
1084
|
{...(inlineGlyph ? { marginInlineStart: "$2" as const } : undefined)}
|
|
1049
|
-
|
|
1085
|
+
// The glass rounds itself, unclipped.
|
|
1086
|
+
{...(GlassView ? { borderRadius: 100000 } : undefined)}
|
|
1050
1087
|
{...(confirmPlate ? { borderRadius: 100000 } : undefined)}
|
|
1051
1088
|
{...(mediaPlate
|
|
1052
1089
|
? {
|
|
1053
1090
|
borderRadius: 100000,
|
|
1054
1091
|
backgroundColor: "$shadow4",
|
|
1055
|
-
...(isWeb
|
|
1056
|
-
? {
|
|
1057
|
-
style: {
|
|
1058
|
-
backdropFilter: "blur(16px) saturate(180%)",
|
|
1059
|
-
WebkitBackdropFilter: "blur(16px) saturate(180%)",
|
|
1060
|
-
},
|
|
1061
|
-
}
|
|
1062
|
-
: undefined),
|
|
1092
|
+
...(isWeb ? { style: MEDIA_PLATE_WEB_STYLE } : undefined),
|
|
1063
1093
|
}
|
|
1064
1094
|
: undefined)}
|
|
1065
1095
|
{...(edge && !inlineGlyph && chromeless && !selectedFill && !isCircular
|
|
@@ -1221,7 +1251,14 @@ export function Button({
|
|
|
1221
1251
|
glassEffectStyle="regular"
|
|
1222
1252
|
isInteractive
|
|
1223
1253
|
pointerEvents="none"
|
|
1224
|
-
style={{
|
|
1254
|
+
style={{
|
|
1255
|
+
position: "absolute",
|
|
1256
|
+
top: 0,
|
|
1257
|
+
right: 0,
|
|
1258
|
+
bottom: 0,
|
|
1259
|
+
left: 0,
|
|
1260
|
+
borderRadius: visualPx / 2,
|
|
1261
|
+
}}
|
|
1225
1262
|
/>
|
|
1226
1263
|
) : null}
|
|
1227
1264
|
{iconElement}
|
|
@@ -1292,3 +1329,6 @@ export interface IconButtonProps extends Omit<
|
|
|
1292
1329
|
export function IconButton(props: IconButtonProps) {
|
|
1293
1330
|
return <Button {...props} />;
|
|
1294
1331
|
}
|
|
1332
|
+
|
|
1333
|
+
export { IconButtonGroup, ICON_BUTTON_GLASS_MERGE_PX } from "./IconButtonGroup";
|
|
1334
|
+
export type { IconButtonGroupProps } from "./IconButtonGroup";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LC-176: the media plate's material on web, where a blur behind the plate is
|
|
3
|
+
* the platform's material; native keeps the translucent ground alone. One
|
|
4
|
+
* copy, shared by a lone plate and a group's capsule.
|
|
5
|
+
*/
|
|
6
|
+
export const MEDIA_PLATE_WEB_STYLE = {
|
|
7
|
+
backdropFilter: "blur(16px) saturate(180%)",
|
|
8
|
+
WebkitBackdropFilter: "blur(16px) saturate(180%)",
|
|
9
|
+
} as const;
|
|
@@ -124,3 +124,72 @@ describe("FloatingPanel native ContextMenu at the long-press point", () => {
|
|
|
124
124
|
expect(sheet()).toBeNull();
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
|
+
|
|
128
|
+
function Glyph(_: { onPress: () => void; "aria-label": string }) {
|
|
129
|
+
return <Text>◐</Text>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function GlyphPanel({ onPress, anchored = false }: { onPress: () => void; anchored?: boolean }) {
|
|
133
|
+
const [open, setOpen] = useState(false);
|
|
134
|
+
return (
|
|
135
|
+
<FloatingPanel
|
|
136
|
+
open={open}
|
|
137
|
+
onOpenChange={setOpen}
|
|
138
|
+
openOn="contextmenu"
|
|
139
|
+
triggerSizing="content"
|
|
140
|
+
{...(anchored
|
|
141
|
+
? { compactFace: "menu" as const, anchorMode: "attach" as const, triggerEcho: false }
|
|
142
|
+
: null)}
|
|
143
|
+
trigger={<Glyph onPress={onPress} aria-label="Appearance" />}
|
|
144
|
+
>
|
|
145
|
+
<Text>Dark</Text>
|
|
146
|
+
</FloatingPanel>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function tap(target: Element) {
|
|
151
|
+
act(() => {
|
|
152
|
+
target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, button: 0 }));
|
|
153
|
+
vi.advanceTimersByTime(100);
|
|
154
|
+
target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, button: 0 }));
|
|
155
|
+
target.dispatchEvent(new MouseEvent("click", { bubbles: true, button: 0 }));
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
describe("FloatingPanel native ContextMenu keeps its trigger's tap (FZ-8158)", () => {
|
|
160
|
+
it("runs the trigger's own onPress on a tap and names the button after it", () => {
|
|
161
|
+
screen.width = 390;
|
|
162
|
+
screen.height = 844;
|
|
163
|
+
const onPress = vi.fn();
|
|
164
|
+
const result = renderWithProviders(<GlyphPanel onPress={onPress} />);
|
|
165
|
+
tap(result.getByRole("button", { name: "Appearance" }));
|
|
166
|
+
expect(onPress).toHaveBeenCalledTimes(1);
|
|
167
|
+
expect(sheet()).toBeNull();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("opens the menu on a long-press without running the tap", () => {
|
|
171
|
+
screen.width = 390;
|
|
172
|
+
screen.height = 844;
|
|
173
|
+
const onPress = vi.fn();
|
|
174
|
+
const result = renderWithProviders(<GlyphPanel onPress={onPress} />);
|
|
175
|
+
longPress(result.getByRole("button", { name: "Appearance" }), 200, 300);
|
|
176
|
+
expect(sheet()).not.toBeNull();
|
|
177
|
+
expect(onPress).not.toHaveBeenCalled();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("opens as the pull-down under its trigger on a phone when menu-faced, never a sheet (FZ-8158 r5)", () => {
|
|
181
|
+
screen.width = 390;
|
|
182
|
+
screen.height = 844;
|
|
183
|
+
const onPress = vi.fn();
|
|
184
|
+
const result = renderWithProviders(<GlyphPanel onPress={onPress} anchored />);
|
|
185
|
+
longPress(result.getByRole("button", { name: "Appearance" }), 200, 300);
|
|
186
|
+
act(() => {
|
|
187
|
+
vi.advanceTimersByTime(1);
|
|
188
|
+
});
|
|
189
|
+
expect(document.querySelector('[data-testid="floating-panel-menu"]')).not.toBeNull();
|
|
190
|
+
expect(document.querySelector('[data-testid="floating-panel-menu-echo"]')).toBeNull();
|
|
191
|
+
expect(sheet()).toBeNull();
|
|
192
|
+
expect(pointPanel()).toBeNull();
|
|
193
|
+
expect(onPress).not.toHaveBeenCalled();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
* ContextMenu (`openOn="contextmenu"`): long-press opens it. On a window wider
|
|
55
55
|
* than OVERLAY_BREAKPOINT (a tablet) it opens at the long-press point, the
|
|
56
56
|
* same free overlay the web draws at the pointer; a phone keeps the sheet,
|
|
57
|
-
* as web does at ≤640.
|
|
57
|
+
* as web does at ≤640. With `compactFace="menu"` it opens as the pull-down at
|
|
58
|
+
* its trigger instead, at every width (a bar button's long-press, FZ-8158).
|
|
58
59
|
*
|
|
59
60
|
* Regular width (FZ-8116, LC-266): on an iPad or any window wider than
|
|
60
61
|
* OVERLAY_BREAKPOINT the sheet is the wrong form. The panel opens over its
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
|
|
65
66
|
import { nativeAnimationConfig, type MotionStop } from "@multiplatform.one/theme";
|
|
66
67
|
import {
|
|
68
|
+
isValidElement,
|
|
67
69
|
type ReactNode,
|
|
68
70
|
useCallback,
|
|
69
71
|
useContext,
|
|
@@ -208,10 +210,25 @@ export function FloatingPanel({
|
|
|
208
210
|
[disabled, onOpenChange],
|
|
209
211
|
);
|
|
210
212
|
const isContextMenu = openOn === "contextmenu";
|
|
213
|
+
// A long-press menu never eats its trigger's tap: the web lets the primary
|
|
214
|
+
// click through to the trigger, so here the Pressable that owns the gesture
|
|
215
|
+
// runs the trigger's own onPress and carries its name.
|
|
216
|
+
const triggerOwn =
|
|
217
|
+
isContextMenu && isValidElement(trigger)
|
|
218
|
+
? (trigger.props as {
|
|
219
|
+
onPress?: (event: GestureResponderEvent) => void;
|
|
220
|
+
"aria-label"?: string;
|
|
221
|
+
accessibilityLabel?: string;
|
|
222
|
+
})
|
|
223
|
+
: undefined;
|
|
224
|
+
const triggerLabel =
|
|
225
|
+
triggerA11y?.label ?? triggerOwn?.["aria-label"] ?? triggerOwn?.accessibilityLabel;
|
|
211
226
|
const regular = overlaySizeClass(windowWidth) === "regular";
|
|
212
227
|
const atPoint = isContextMenu && pressPoint !== null && regular;
|
|
213
228
|
const insideOverlay = useInsideOverlay();
|
|
214
|
-
const asMenu =
|
|
229
|
+
const asMenu = isContextMenu
|
|
230
|
+
? compactFace === "menu"
|
|
231
|
+
: resolveCompactFace(compactFace, insideOverlay) === "menu";
|
|
215
232
|
const asRegular = regular && !asMenu && !isContextMenu && sheet !== true;
|
|
216
233
|
const anchored = asMenu || asRegular;
|
|
217
234
|
const triggerRef = useRef<RNView | null>(null);
|
|
@@ -543,12 +560,16 @@ export function FloatingPanel({
|
|
|
543
560
|
>
|
|
544
561
|
<Pressable
|
|
545
562
|
{...(isContextMenu
|
|
546
|
-
? {
|
|
563
|
+
? {
|
|
564
|
+
onLongPress: handleTriggerLongPress,
|
|
565
|
+
delayLongPress: 500,
|
|
566
|
+
...(triggerOwn?.onPress && !disabled ? { onPress: triggerOwn.onPress } : undefined),
|
|
567
|
+
}
|
|
547
568
|
: { onPress: handleTriggerPress })}
|
|
548
569
|
disabled={disabled}
|
|
549
570
|
accessibilityRole="button"
|
|
550
571
|
accessibilityState={{ disabled: !!disabled, expanded: !!open }}
|
|
551
|
-
{...(
|
|
572
|
+
{...(triggerLabel ? { accessibilityLabel: triggerLabel } : undefined)}
|
|
552
573
|
{...(triggerA11y?.value
|
|
553
574
|
? { accessibilityValue: { text: triggerA11y.value } }
|
|
554
575
|
: undefined)}
|
|
@@ -67,11 +67,15 @@ describe("FileUpload", () => {
|
|
|
67
67
|
const result = renderWithProviders(
|
|
68
68
|
<FileUpload existing={{ src: "/files/sprite.png" }} onExistingRemove={remove} />,
|
|
69
69
|
);
|
|
70
|
-
// LC-260: Replace and Remove are glyphs
|
|
70
|
+
// LC-260: Replace and Remove are glyphs over the image; LC-176 puts the
|
|
71
|
+
// pair in one shared media capsule, so the buttons draw glyphs alone.
|
|
71
72
|
const actions = result.container.querySelector('[data-file-upload="preview-actions"]');
|
|
73
|
+
const capsule = actions?.querySelector('[data-mp-icon-button-group="media"]');
|
|
74
|
+
expect(capsule?.querySelector('[aria-label="Replace"]')).toBeTruthy();
|
|
75
|
+
expect(capsule?.querySelector('[aria-label^="Remove"]')).toBeTruthy();
|
|
72
76
|
expect(
|
|
73
|
-
|
|
74
|
-
).toBe("media");
|
|
77
|
+
capsule?.querySelector('[aria-label="Replace"]')?.getAttribute("data-mp-icon-button"),
|
|
78
|
+
).not.toBe("media");
|
|
75
79
|
expect(result.container.textContent).not.toContain("Replace");
|
|
76
80
|
expect(result.container.textContent).not.toContain("Choose File");
|
|
77
81
|
expect(result.container.textContent).not.toContain("Drag a file");
|
|
@@ -349,7 +353,7 @@ describe("FileUpload bento-derived dropzone (MPO-57)", () => {
|
|
|
349
353
|
expect(zone.textContent).toContain("Drag a file into this area");
|
|
350
354
|
});
|
|
351
355
|
|
|
352
|
-
it("renders picked files as in-zone rows: name, bold size line, bare
|
|
356
|
+
it("renders picked files as in-zone rows: name, bold size line, bare remove glyph (29 painted, hitSlop 44)", async () => {
|
|
353
357
|
const { container } = renderWithHouseThemes(
|
|
354
358
|
<FileUpload label="Attachment" name="attachment" multiple />,
|
|
355
359
|
);
|
|
@@ -372,13 +376,13 @@ describe("FileUpload bento-derived dropzone (MPO-57)", () => {
|
|
|
372
376
|
expect(sizeLine).toBeTruthy();
|
|
373
377
|
expect(sizeLine.className).toMatch(/_fow-700/);
|
|
374
378
|
|
|
375
|
-
// Remove: LC-176
|
|
376
|
-
//
|
|
377
|
-
// The filled $color12 disc it replaced read as a plate on plain content.
|
|
379
|
+
// Remove: LC-176 bare ✕, no disc or fill, painted at nestedControl (29)
|
|
380
|
+
// with hitSlop restoring the 44 floor (data-mp-press-slop 8 → 29+16=45).
|
|
378
381
|
const remove = flist.querySelector('[aria-label="Remove hello.txt"]') as HTMLElement;
|
|
379
382
|
expect(remove).toBeTruthy();
|
|
380
383
|
expect(remove.getAttribute("data-nested-px")).toBe("29");
|
|
381
384
|
expect(remove.getAttribute("data-mp-press-slop")).toBe("8");
|
|
385
|
+
expect(remove.className).toMatch(/_bg-transparent/);
|
|
382
386
|
expect(remove.className).not.toMatch(/_bg-color12/);
|
|
383
387
|
expect(remove.querySelector("svg")).toBeTruthy();
|
|
384
388
|
// The caption is dropped once files exist; the CTA stays.
|
|
@@ -5,7 +5,7 @@ import type { DeepKeys, DeepValue } from "@tanstack/form-core";
|
|
|
5
5
|
import { type DragEvent, type ReactNode, useCallback, useEffect, useRef, useState } from "react";
|
|
6
6
|
import { useMedia, useProps, type SizeTokens } from "tamagui";
|
|
7
7
|
import { Image, isWeb, Text, XStack, YStack, styled } from "tamagui";
|
|
8
|
-
import { Button, IconButton } from "../../Button";
|
|
8
|
+
import { Button, IconButton, IconButtonGroup } from "../../Button";
|
|
9
9
|
import { standardActions } from "../../standardActions";
|
|
10
10
|
import { Field, FieldLayout } from "../../fieldLayout";
|
|
11
11
|
import { Skeleton } from "../../Skeleton";
|
|
@@ -1092,7 +1092,9 @@ export function FileUpload<
|
|
|
1092
1092
|
zIndex={1}
|
|
1093
1093
|
{...knobProps.gap}
|
|
1094
1094
|
>
|
|
1095
|
-
|
|
1095
|
+
<IconButtonGroup plate="media">
|
|
1096
|
+
{previewActions(true, onValueChange)}
|
|
1097
|
+
</IconButtonGroup>
|
|
1096
1098
|
</XStack>
|
|
1097
1099
|
) : null}
|
|
1098
1100
|
</YStack>
|
package/src/index.ts
CHANGED
|
@@ -115,11 +115,19 @@ export type { ActionLabelParts } from "./actionLabel";
|
|
|
115
115
|
export {
|
|
116
116
|
Button,
|
|
117
117
|
IconButton,
|
|
118
|
+
IconButtonGroup,
|
|
119
|
+
iconButtonGlyphPx,
|
|
120
|
+
ICON_BUTTON_GLASS_MERGE_PX,
|
|
118
121
|
ICON_BUTTON_GLYPH_PX,
|
|
119
122
|
ICON_BUTTON_NEUTRAL_GLYPH_PX,
|
|
120
123
|
ICON_BUTTON_PRESS_OPACITY,
|
|
121
124
|
} from "./Button";
|
|
122
|
-
export type {
|
|
125
|
+
export type {
|
|
126
|
+
ButtonProps,
|
|
127
|
+
ButtonActionRole,
|
|
128
|
+
IconButtonGroupProps,
|
|
129
|
+
IconButtonProps,
|
|
130
|
+
} from "./Button";
|
|
123
131
|
|
|
124
132
|
export { Input } from "./fields/Input";
|
|
125
133
|
export type { InputProps } from "./fields/Input";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type XStackProps } from "tamagui";
|
|
3
|
+
/**
|
|
4
|
+
* LC-176: how far apart two Liquid Glass circles may sit and still merge. Half
|
|
5
|
+
* the 44pt target, so neighbours on the bar's gap always join.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ICON_BUTTON_GLASS_MERGE_PX = 22;
|
|
8
|
+
export interface IconButtonGroupProps extends XStackProps {
|
|
9
|
+
/** Over imagery or video: the group shares one material capsule. */
|
|
10
|
+
plate?: "media";
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* LC-176: icon buttons that sit side by side. Grounds merge, they never stand
|
|
15
|
+
* as a row of separate circles: on iOS 26 the bar's group is one Liquid Glass
|
|
16
|
+
* capsule, as the system draws a bar's item group (merging each circle through
|
|
17
|
+
* the glass container left a waist between them, FZ-8158); over media the
|
|
18
|
+
* group shares one material capsule; a bare row stays bare. A lone button
|
|
19
|
+
* keeps its own circle.
|
|
20
|
+
*/
|
|
21
|
+
export declare function IconButtonGroup({ plate, children, ...rest }: IconButtonGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=IconButtonGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconButtonGroup.d.ts","sourceRoot":"","sources":["../../src/Button/IconButtonGroup.tsx"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAKvE;;;GAGG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,oBAAoB,2CA2DjF"}
|