@multiplatform.one/forms 7.67.0 → 7.68.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.cjs +45 -5
- package/dist/cjs/AdaptivePopup/index.native.js +48 -6
- package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
- package/dist/cjs/Button/glass.cjs +30 -0
- package/dist/cjs/Button/glass.native.js +47 -0
- package/dist/cjs/Button/glass.native.js.map +1 -0
- package/dist/cjs/Button/index.cjs +157 -28
- package/dist/cjs/Button/index.native.js +158 -29
- package/dist/cjs/Button/index.native.js.map +1 -1
- 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.cjs +6 -8
- package/dist/cjs/ContextualSaveBar/index.native.js +9 -11
- 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.cjs +0 -1
- package/dist/cjs/DescriptionList/index.native.js +2 -3
- 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/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.cjs +7 -8
- package/dist/cjs/fields/Barcode/BarcodeScanner.native.js +8 -9
- package/dist/cjs/fields/Barcode/BarcodeScanner.native.js.map +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 +83 -60
- package/dist/cjs/fields/FileUpload/index.native.js +98 -75
- 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.cjs +7 -8
- package/dist/cjs/fields/Geolocation/index.native.js +12 -13
- 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.cjs +4 -6
- package/dist/cjs/fields/ImageField/index.native.js +6 -8
- 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.cjs +20 -28
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +20 -28
- 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 +8 -1
- package/dist/cjs/index.native.js +52 -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.cjs +0 -8
- package/dist/cjs/shared/colorRamps.native.js +0 -8
- 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.cjs +117 -0
- package/dist/cjs/standardActions.native.js +120 -0
- package/dist/cjs/standardActions.native.js.map +1 -0
- 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/AdaptivePopup/index.mjs +45 -5
- package/dist/esm/AdaptivePopup/index.mjs.map +1 -1
- package/dist/esm/AdaptivePopup/index.native.js +47 -5
- package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
- package/dist/esm/Button/glass.mjs +5 -0
- package/dist/esm/Button/glass.mjs.map +1 -0
- package/dist/esm/Button/glass.native.js +19 -0
- package/dist/esm/Button/glass.native.js.map +1 -0
- package/dist/esm/Button/index.mjs +153 -28
- package/dist/esm/Button/index.mjs.map +1 -1
- package/dist/esm/Button/index.native.js +153 -28
- package/dist/esm/Button/index.native.js.map +1 -1
- package/dist/esm/ContextualSaveBar/index.mjs +7 -9
- package/dist/esm/ContextualSaveBar/index.mjs.map +1 -1
- package/dist/esm/ContextualSaveBar/index.native.js +7 -9
- package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
- package/dist/esm/DescriptionList/index.mjs +0 -1
- package/dist/esm/DescriptionList/index.mjs.map +1 -1
- package/dist/esm/DescriptionList/index.native.js +0 -1
- package/dist/esm/DescriptionList/index.native.js.map +1 -1
- package/dist/esm/fields/Barcode/BarcodeScanner.mjs +8 -9
- package/dist/esm/fields/Barcode/BarcodeScanner.mjs.map +1 -1
- package/dist/esm/fields/Barcode/BarcodeScanner.native.js +8 -9
- package/dist/esm/fields/Barcode/BarcodeScanner.native.js.map +1 -1
- package/dist/esm/fields/FileUpload/index.mjs +84 -61
- package/dist/esm/fields/FileUpload/index.mjs.map +1 -1
- package/dist/esm/fields/FileUpload/index.native.js +97 -74
- package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
- package/dist/esm/fields/Geolocation/index.mjs +8 -9
- package/dist/esm/fields/Geolocation/index.mjs.map +1 -1
- package/dist/esm/fields/Geolocation/index.native.js +8 -9
- package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
- package/dist/esm/fields/ImageField/index.mjs +6 -8
- package/dist/esm/fields/ImageField/index.mjs.map +1 -1
- package/dist/esm/fields/ImageField/index.native.js +6 -8
- package/dist/esm/fields/ImageField/index.native.js.map +1 -1
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +20 -28
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +20 -28
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/esm/index.mjs +3 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +3 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/shared/colorRamps.mjs +0 -8
- package/dist/esm/shared/colorRamps.mjs.map +1 -1
- package/dist/esm/shared/colorRamps.native.js +0 -8
- package/dist/esm/shared/colorRamps.native.js.map +1 -1
- package/dist/esm/standardActions.mjs +91 -0
- package/dist/esm/standardActions.mjs.map +1 -0
- package/dist/esm/standardActions.native.js +91 -0
- package/dist/esm/standardActions.native.js.map +1 -0
- package/dist/jsx/AdaptivePopup/index.mjs +45 -5
- package/dist/jsx/AdaptivePopup/index.mjs.map +1 -1
- package/dist/jsx/AdaptivePopup/index.native.js +47 -5
- package/dist/jsx/AdaptivePopup/index.native.js.map +1 -1
- package/dist/jsx/Button/glass.mjs +5 -0
- package/dist/jsx/Button/glass.mjs.map +1 -0
- package/dist/jsx/Button/glass.native.js +47 -0
- package/dist/jsx/Button/glass.native.js.map +1 -0
- package/dist/jsx/Button/index.mjs +153 -28
- package/dist/jsx/Button/index.mjs.map +1 -1
- package/dist/jsx/Button/index.native.js +156 -27
- package/dist/jsx/Button/index.native.js.map +1 -1
- package/dist/jsx/ContextualSaveBar/index.mjs +7 -9
- package/dist/jsx/ContextualSaveBar/index.mjs.map +1 -1
- package/dist/jsx/ContextualSaveBar/index.native.js +6 -8
- package/dist/jsx/ContextualSaveBar/index.native.js.map +1 -1
- package/dist/jsx/DescriptionList/index.mjs +0 -1
- package/dist/jsx/DescriptionList/index.mjs.map +1 -1
- package/dist/jsx/DescriptionList/index.native.js +0 -1
- package/dist/jsx/DescriptionList/index.native.js.map +1 -1
- package/dist/jsx/fields/Barcode/BarcodeScanner.mjs +8 -9
- package/dist/jsx/fields/Barcode/BarcodeScanner.mjs.map +1 -1
- package/dist/jsx/fields/Barcode/BarcodeScanner.native.js +7 -8
- package/dist/jsx/fields/Barcode/BarcodeScanner.native.js.map +1 -1
- package/dist/jsx/fields/FileUpload/index.mjs +84 -61
- package/dist/jsx/fields/FileUpload/index.mjs.map +1 -1
- package/dist/jsx/fields/FileUpload/index.native.js +96 -73
- package/dist/jsx/fields/FileUpload/index.native.js.map +1 -1
- package/dist/jsx/fields/Geolocation/index.mjs +8 -9
- package/dist/jsx/fields/Geolocation/index.mjs.map +1 -1
- package/dist/jsx/fields/Geolocation/index.native.js +7 -8
- package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
- package/dist/jsx/fields/ImageField/index.mjs +6 -8
- package/dist/jsx/fields/ImageField/index.mjs.map +1 -1
- package/dist/jsx/fields/ImageField/index.native.js +4 -6
- package/dist/jsx/fields/ImageField/index.native.js.map +1 -1
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +20 -28
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +20 -28
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/jsx/index.js +3 -2
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +3 -2
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +7 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/shared/colorRamps.mjs +0 -8
- package/dist/jsx/shared/colorRamps.mjs.map +1 -1
- package/dist/jsx/shared/colorRamps.native.js +0 -8
- package/dist/jsx/shared/colorRamps.native.js.map +1 -1
- package/dist/jsx/standardActions.mjs +91 -0
- package/dist/jsx/standardActions.mjs.map +1 -0
- package/dist/jsx/standardActions.native.js +120 -0
- package/dist/jsx/standardActions.native.js.map +1 -0
- package/package.json +12 -8
- package/src/AdaptivePopup/AdaptivePopup.spec.tsx +44 -0
- package/src/AdaptivePopup/AdaptivePopup.stories.tsx +12 -32
- package/src/AdaptivePopup/index.tsx +65 -13
- package/src/Button/Button.disabledGlyph.spec.tsx +111 -0
- package/src/Button/Button.iconButton.spec.tsx +279 -0
- package/src/Button/Button.stories.tsx +59 -3
- package/src/Button/glass.native.ts +38 -0
- package/src/Button/glass.ts +18 -0
- package/src/Button/index.tsx +272 -40
- package/src/ContextualSaveBar/ContextualSaveBar.spec.tsx +3 -1
- package/src/ContextualSaveBar/ContextualSaveBar.stories.tsx +2 -2
- package/src/ContextualSaveBar/index.tsx +7 -10
- package/src/ControlGroup/ControlGroup.stories.tsx +3 -2
- package/src/DescriptionList/index.tsx +0 -1
- package/src/ErrorSummary.stories.tsx +2 -1
- package/src/FieldLayout.stories.tsx +3 -2
- package/src/FloatingPanel/FloatingPanel.stories.tsx +6 -10
- package/src/Form/Form.stories.tsx +6 -5
- package/src/errorSummaryStories.spec.tsx +4 -4
- package/src/fields/Barcode/BarcodeScanner.native.tsx +10 -9
- package/src/fields/Barcode/BarcodeScanner.tsx +10 -9
- package/src/fields/Checkbox/Checkbox.stories.tsx +3 -3
- package/src/fields/Checkbox/CheckboxGroup.stories.tsx +2 -2
- package/src/fields/ColorPicker/ColorPicker.stories.tsx +2 -2
- package/src/fields/Combobox/Combobox.stories.tsx +2 -2
- package/src/fields/DatePicker/DatePicker.stories.tsx +2 -1
- package/src/fields/DatePicker/DateRangePicker.stories.tsx +2 -2
- package/src/fields/DatePicker/DatetimePicker.stories.tsx +2 -1
- package/src/fields/DatePicker/MonthPicker.stories.tsx +2 -2
- package/src/fields/DatePicker/MultiDatePicker.stories.tsx +2 -2
- package/src/fields/FileUpload/FileUpload.spec.tsx +11 -6
- package/src/fields/FileUpload/FileUpload.stories.tsx +2 -2
- package/src/fields/FileUpload/index.tsx +101 -77
- package/src/fields/Geolocation/index.tsx +12 -7
- package/src/fields/ImageField/ImageField.spec.tsx +5 -5
- package/src/fields/ImageField/ImageField.stories.tsx +2 -2
- package/src/fields/ImageField/index.tsx +6 -9
- package/src/fields/Input/Input.stories.tsx +2 -2
- package/src/fields/MentionInput/MentionInput.stories.tsx +2 -1
- package/src/fields/Progress/Progress.stories.tsx +2 -1
- package/src/fields/RadioGroup/RadioGroup.stories.tsx +2 -1
- package/src/fields/Signature/Signature.stories.tsx +2 -2
- package/src/fields/Stepper/Stepper.stories.tsx +2 -2
- package/src/fields/TextArea/TextArea.stories.tsx +2 -2
- package/src/fields/ToggleGroup/ToggleGroup.stories.tsx +2 -2
- package/src/fields/nativeDateTime/OsDateTimeSheet.presentation.spec.tsx +6 -5
- package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +24 -12
- package/src/index.ts +10 -2
- package/src/shared/colorRamps.ts +1 -11
- package/src/standardActions.ts +96 -0
- package/types/AdaptivePopup/index.d.ts +13 -1
- package/types/AdaptivePopup/index.d.ts.map +1 -1
- package/types/Button/glass.d.ts +15 -0
- package/types/Button/glass.d.ts.map +1 -0
- package/types/Button/glass.native.d.ts +11 -0
- package/types/Button/glass.native.d.ts.map +1 -0
- package/types/Button/index.d.ts +45 -1
- package/types/Button/index.d.ts.map +1 -1
- package/types/ContextualSaveBar/index.d.ts.map +1 -1
- package/types/DescriptionList/index.d.ts.map +1 -1
- package/types/fields/Barcode/BarcodeScanner.d.ts.map +1 -1
- package/types/fields/Barcode/BarcodeScanner.native.d.ts.map +1 -1
- package/types/fields/FileUpload/index.d.ts.map +1 -1
- package/types/fields/Geolocation/index.d.ts.map +1 -1
- package/types/fields/ImageField/index.d.ts.map +1 -1
- package/types/fields/nativeDateTime/OsDateTimeSheet.d.ts.map +1 -1
- package/types/index.d.ts +4 -2
- package/types/index.d.ts.map +1 -1
- package/types/shared/colorRamps.d.ts +1 -11
- package/types/shared/colorRamps.d.ts.map +1 -1
- package/types/standardActions.d.ts +24 -0
- package/types/standardActions.d.ts.map +1 -0
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
YStack,
|
|
28
28
|
} from "tamagui";
|
|
29
29
|
import { X } from "@tamagui/lucide-icons-2";
|
|
30
|
+
import { IconButton } from "../Button";
|
|
31
|
+
import { standardActions } from "../standardActions";
|
|
30
32
|
import { formCommonColors } from "../shared/colorRamps";
|
|
31
33
|
import { useReturnFocusOnClose, useSheetModalFocus } from "../shared/focusManagement";
|
|
32
34
|
import { t } from "../shared/t";
|
|
@@ -71,6 +73,18 @@ export interface AdaptivePopupProps {
|
|
|
71
73
|
showCloseButton?: boolean;
|
|
72
74
|
/** Custom footer content (e.g. action buttons) */
|
|
73
75
|
footer?: ReactNode;
|
|
76
|
+
/**
|
|
77
|
+
* LC-260: the popup's one confirm. The header becomes the iOS 26 sheet
|
|
78
|
+
* bar: cancel (X) leading, the title centred, the accent check trailing,
|
|
79
|
+
* and the corner close goes.
|
|
80
|
+
*/
|
|
81
|
+
onConfirm?: () => void;
|
|
82
|
+
confirmKind?: "confirm" | "done" | "save" | "submit";
|
|
83
|
+
/** The confirm's accessible name when its kind is too thin ("Save profile"). */
|
|
84
|
+
confirmLabel?: string;
|
|
85
|
+
confirmDisabled?: boolean;
|
|
86
|
+
confirmDisabledReason?: string;
|
|
87
|
+
confirmLoading?: boolean;
|
|
74
88
|
/** Whether to disable the trigger */
|
|
75
89
|
disabled?: boolean;
|
|
76
90
|
}
|
|
@@ -210,6 +224,12 @@ export function AdaptivePopup({
|
|
|
210
224
|
showCloseButton = true,
|
|
211
225
|
footer,
|
|
212
226
|
disabled,
|
|
227
|
+
onConfirm,
|
|
228
|
+
confirmKind = "done",
|
|
229
|
+
confirmLabel,
|
|
230
|
+
confirmDisabled,
|
|
231
|
+
confirmDisabledReason,
|
|
232
|
+
confirmLoading,
|
|
213
233
|
}: AdaptivePopupProps) {
|
|
214
234
|
const { knobProps } = useResolvedKnobs({ painted: false });
|
|
215
235
|
const { knobProps: nestedKnobs } = useResolvedKnobs();
|
|
@@ -282,22 +302,54 @@ export function AdaptivePopup({
|
|
|
282
302
|
: { onPress: openFromTrigger }),
|
|
283
303
|
};
|
|
284
304
|
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
305
|
+
const confirms = onConfirm != null;
|
|
306
|
+
const cornerClose = showCloseButton && !confirms;
|
|
307
|
+
const confirmBar = confirms && (
|
|
308
|
+
<XStack alignItems="center" data-mp-overlay-header="confirm" {...knobProps.gapSm}>
|
|
309
|
+
<IconButton
|
|
310
|
+
icon={standardActions.cancel.icon}
|
|
311
|
+
aria-label={t("Cancel")}
|
|
312
|
+
data-testid="adaptive-popup-cancel"
|
|
313
|
+
onPress={() => onOpenChange(false)}
|
|
314
|
+
/>
|
|
315
|
+
<XStack flex={1} minWidth={0} justifyContent="center">
|
|
293
316
|
{title ? (
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
</
|
|
317
|
+
<Dialog.Title {...knobProps.heading} textAlign="center">
|
|
318
|
+
{title}
|
|
319
|
+
</Dialog.Title>
|
|
297
320
|
) : null}
|
|
298
321
|
</XStack>
|
|
299
|
-
|
|
322
|
+
<IconButton
|
|
323
|
+
icon={standardActions[confirmKind].icon}
|
|
324
|
+
plate="primary"
|
|
325
|
+
aria-label={confirmLabel ?? t(standardActions[confirmKind].label)}
|
|
326
|
+
data-testid="adaptive-popup-confirm"
|
|
327
|
+
loading={confirmLoading}
|
|
328
|
+
disabled={confirmDisabled}
|
|
329
|
+
disabledReason={confirmDisabledReason}
|
|
330
|
+
disabledReasonPlacement="inline"
|
|
331
|
+
onPress={onConfirm}
|
|
332
|
+
/>
|
|
333
|
+
</XStack>
|
|
300
334
|
);
|
|
335
|
+
const headerContent = confirms
|
|
336
|
+
? confirmBar
|
|
337
|
+
: (title || showCloseButton) && (
|
|
338
|
+
<Unspaced>
|
|
339
|
+
<XStack
|
|
340
|
+
justifyContent="space-between"
|
|
341
|
+
alignItems="center"
|
|
342
|
+
paddingRight={cornerClose ? closePx : undefined}
|
|
343
|
+
minHeight={cornerClose ? closePx : undefined}
|
|
344
|
+
>
|
|
345
|
+
{title ? (
|
|
346
|
+
<YStack flex={1}>
|
|
347
|
+
<Dialog.Title {...knobProps.heading}>{title}</Dialog.Title>
|
|
348
|
+
</YStack>
|
|
349
|
+
) : null}
|
|
350
|
+
</XStack>
|
|
351
|
+
</Unspaced>
|
|
352
|
+
);
|
|
301
353
|
|
|
302
354
|
const footerContent = footer && <YStack paddingTop="$2">{footer}</YStack>;
|
|
303
355
|
|
|
@@ -320,7 +372,7 @@ export function AdaptivePopup({
|
|
|
320
372
|
)}
|
|
321
373
|
<YStack flex={size === "fullscreen" ? 1 : undefined}>{children}</YStack>
|
|
322
374
|
{footerContent}
|
|
323
|
-
{
|
|
375
|
+
{cornerClose ? <PopupCloseButton onPress={() => onOpenChange(false)} /> : null}
|
|
324
376
|
</YStack>
|
|
325
377
|
);
|
|
326
378
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*
|
|
4
|
+
* LC-40 DISABLED-VISIBLE for a frameless control (FZ-7889 round 4). A
|
|
5
|
+
* disabled chromeless Button is its enabled twin dimmed: the same transparent
|
|
6
|
+
* frame and ink, at the recipe's glyph opacity. The keepLabel wash once
|
|
7
|
+
* filled it, so a pager's first-page chevron read as more prominent than the
|
|
8
|
+
* enabled next chevron beside it.
|
|
9
|
+
*
|
|
10
|
+
* jsdom cascades no Tamagui CSS, so this reads the atomic classes each frame
|
|
11
|
+
* asks for and the opacity rule behind its `_o-` class.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
15
|
+
import { createDefaultThemeConfig, Preset } from "@multiplatform.one/theme";
|
|
16
|
+
import type { ReactElement } from "react";
|
|
17
|
+
import { TamaguiProvider, YStack } from "tamagui";
|
|
18
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
19
|
+
import { Button } from "./index";
|
|
20
|
+
|
|
21
|
+
afterEach(cleanup);
|
|
22
|
+
|
|
23
|
+
const houseConfig = createDefaultThemeConfig();
|
|
24
|
+
|
|
25
|
+
const SCHEMES = ["light", "dark"] as const;
|
|
26
|
+
|
|
27
|
+
function houseRender(ui: ReactElement, scheme: string, disabledStyle = "keepLabel") {
|
|
28
|
+
return render(
|
|
29
|
+
<TamaguiProvider config={houseConfig.tamagui} defaultTheme={scheme} disableInjectCSS>
|
|
30
|
+
<Preset overrides={{ disabledStyle: disabledStyle as "keepLabel" | "dimWhole" }}>
|
|
31
|
+
<YStack backgroundColor="$background">{ui}</YStack>
|
|
32
|
+
</Preset>
|
|
33
|
+
</TamaguiProvider>,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function injectedOpacity(className: string): number {
|
|
38
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
39
|
+
for (const rule of Array.from(sheet.cssRules)) {
|
|
40
|
+
if (!(rule instanceof CSSStyleRule)) continue;
|
|
41
|
+
if (!rule.selectorText.endsWith(`.${className}`)) continue;
|
|
42
|
+
const value = rule.style.getPropertyValue("opacity");
|
|
43
|
+
if (value) return Number(value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`no injected opacity rule for .${className}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function opacityOf(el: Element): number {
|
|
50
|
+
const cls = Array.from(el.classList).find((c) => c.startsWith("_o-"));
|
|
51
|
+
return cls ? injectedOpacity(cls) : 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Resting paint classes for one property prefix (`_bg-`, `_col-`, `_bc-`). */
|
|
55
|
+
function rest(el: Element, prefix: string): string[] {
|
|
56
|
+
return Array.from(el.classList)
|
|
57
|
+
.filter((c) => c.startsWith(prefix) && !/0(hover|active|focus|press)/.test(c))
|
|
58
|
+
.sort();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function pair(scheme: string, disabledStyle?: string) {
|
|
62
|
+
houseRender(
|
|
63
|
+
<>
|
|
64
|
+
<Button chromeless aria-label="Next">
|
|
65
|
+
Next
|
|
66
|
+
</Button>
|
|
67
|
+
<Button chromeless aria-label="Previous" disabled>
|
|
68
|
+
Previous
|
|
69
|
+
</Button>
|
|
70
|
+
</>,
|
|
71
|
+
scheme,
|
|
72
|
+
disabledStyle,
|
|
73
|
+
);
|
|
74
|
+
return {
|
|
75
|
+
enabled: screen.getByLabelText("Next"),
|
|
76
|
+
disabled: screen.getByLabelText("Previous"),
|
|
77
|
+
enabledLabel: screen.getByText("Next"),
|
|
78
|
+
disabledLabel: screen.getByText("Previous"),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe("LC-40: a disabled chromeless Button is its enabled twin, dimmed", () => {
|
|
83
|
+
it.each(SCHEMES)("%s keepLabel: no wash, same ink, glyph opacity", (scheme) => {
|
|
84
|
+
const { enabled, disabled, enabledLabel, disabledLabel } = pair(scheme);
|
|
85
|
+
expect(rest(disabled, "_bg-")).toEqual(rest(enabled, "_bg-"));
|
|
86
|
+
expect(rest(disabled, "_bc-")).toEqual(rest(enabled, "_bc-"));
|
|
87
|
+
expect(rest(disabledLabel, "_col-")).toEqual(rest(enabledLabel, "_col-"));
|
|
88
|
+
expect(opacityOf(enabled)).toBe(1);
|
|
89
|
+
expect(opacityOf(disabled)).toBeCloseTo(0.35);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it.each(SCHEMES)("%s dimWhole: no wash, the assembly dim alone", (scheme) => {
|
|
93
|
+
const { enabled, disabled } = pair(scheme, "dimWhole");
|
|
94
|
+
expect(rest(disabled, "_bg-")).toEqual(rest(enabled, "_bg-"));
|
|
95
|
+
expect(opacityOf(disabled)).toBeCloseTo(0.5);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("a framed Button keeps the keepLabel wash", () => {
|
|
99
|
+
houseRender(
|
|
100
|
+
<>
|
|
101
|
+
<Button>Enabled</Button>
|
|
102
|
+
<Button disabled>Disabled</Button>
|
|
103
|
+
</>,
|
|
104
|
+
"light",
|
|
105
|
+
);
|
|
106
|
+
const enabled = screen.getByText("Enabled").closest("[role=button]")!;
|
|
107
|
+
const disabled = screen.getByText("Disabled").closest("[role=button]")!;
|
|
108
|
+
expect(rest(disabled, "_bg-")).not.toEqual(rest(enabled, "_bg-"));
|
|
109
|
+
expect(opacityOf(disabled)).toBe(1);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*
|
|
4
|
+
* LC-176 ICON-BUTTON (FZ-8020). Clay: square or round buttons holding a
|
|
5
|
+
* single icon felt wrong, "it's not supposed to have background or border
|
|
6
|
+
* around it". An icon-only Button paints no plate: a square box on the 44pt
|
|
7
|
+
* slop, and a plate only over media. Round 3 (Clay's compare pick, "USE the
|
|
8
|
+
* native look where possible"): the context picks the treatment. In a bar it
|
|
9
|
+
* is the bar tint, on Liquid Glass where iOS draws it; in content with no
|
|
10
|
+
* intent it is a bold glyph in the text colour.
|
|
11
|
+
*
|
|
12
|
+
* jsdom cascades no Tamagui CSS, so this reads the atomic classes each frame
|
|
13
|
+
* asks for.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
17
|
+
import { createDefaultThemeConfig, Surface } from "@multiplatform.one/theme";
|
|
18
|
+
import type { ReactElement } from "react";
|
|
19
|
+
import { TamaguiProvider, YStack } from "tamagui";
|
|
20
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
21
|
+
import { Button, ICON_BUTTON_GLYPH_PX, ICON_BUTTON_NEUTRAL_GLYPH_PX, IconButton } from "./index";
|
|
22
|
+
|
|
23
|
+
const glass = vi.hoisted(() => ({ available: false }));
|
|
24
|
+
vi.mock("./glass", () => ({
|
|
25
|
+
loadGlassView: () =>
|
|
26
|
+
glass.available ? (props: object) => <div data-glass="" {...props} /> : null,
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
cleanup();
|
|
31
|
+
glass.available = false;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const houseConfig = createDefaultThemeConfig();
|
|
35
|
+
|
|
36
|
+
const SCHEMES = ["light", "dark"] as const;
|
|
37
|
+
|
|
38
|
+
function Glyph({ size, color, weight }: { size?: number; color?: string; weight?: string }) {
|
|
39
|
+
return <svg data-glyph="" data-weight={weight} width={size} height={size} color={color} />;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function glyphOf(label: string): SVGElement {
|
|
43
|
+
return screen.getByLabelText(label).querySelector("[data-glyph]") as SVGElement;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function houseRender(ui: ReactElement, scheme: string) {
|
|
47
|
+
return render(
|
|
48
|
+
<TamaguiProvider config={houseConfig.tamagui} defaultTheme={scheme} disableInjectCSS>
|
|
49
|
+
<YStack backgroundColor="$background">{ui}</YStack>
|
|
50
|
+
</TamaguiProvider>,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Resting paint classes for one property prefix (`_bg-`, `_col-`, `_bc-`). */
|
|
55
|
+
function rest(el: Element, prefix: string): string[] {
|
|
56
|
+
return Array.from(el.classList)
|
|
57
|
+
.filter((c) => c.startsWith(prefix) && !/0(hover|active|focus|press)/.test(c))
|
|
58
|
+
.sort();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe("LC-176: an icon-only Button is a bare glyph", () => {
|
|
62
|
+
it.each(SCHEMES)("%s: in a bar, no fill and no border at rest, the bar tint as ink", (scheme) => {
|
|
63
|
+
houseRender(
|
|
64
|
+
<>
|
|
65
|
+
<Surface bar>
|
|
66
|
+
<Button icon={Glyph} aria-label="More" />
|
|
67
|
+
<Button chromeless accentInk icon={Glyph} aria-label="Bar" />
|
|
68
|
+
</Surface>
|
|
69
|
+
<Button icon={Glyph}>Labelled</Button>
|
|
70
|
+
</>,
|
|
71
|
+
scheme,
|
|
72
|
+
);
|
|
73
|
+
const glyph = screen.getByLabelText("More");
|
|
74
|
+
const bar = screen.getByLabelText("Bar");
|
|
75
|
+
const labelled = screen.getByText("Labelled").closest("[role=button]")!;
|
|
76
|
+
expect(glyph.getAttribute("data-mp-icon-button")).toBe("glyph");
|
|
77
|
+
expect(rest(glyph, "_bg-")).toEqual(rest(bar, "_bg-"));
|
|
78
|
+
expect(rest(glyph, "_bc-")).toEqual(rest(bar, "_bc-"));
|
|
79
|
+
expect(rest(glyph, "_col-")).toEqual(rest(bar, "_col-"));
|
|
80
|
+
expect(rest(glyph, "_bg-")).not.toEqual(rest(labelled, "_bg-"));
|
|
81
|
+
expect(labelled.hasAttribute("data-mp-icon-button")).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("web hover and press light a soft plate", () => {
|
|
85
|
+
houseRender(<Button icon={Glyph} aria-label="More" />, "light");
|
|
86
|
+
const classes = Array.from(screen.getByLabelText("More").classList);
|
|
87
|
+
expect(classes.some((c) => /^_bg-0hover-/.test(c))).toBe(true);
|
|
88
|
+
expect(classes.some((c) => /^_bg-0active-/.test(c))).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("sits in a square box with the press slop", () => {
|
|
92
|
+
houseRender(<Button icon={Glyph} aria-label="More" />, "light");
|
|
93
|
+
const glyph = screen.getByLabelText("More");
|
|
94
|
+
const height = glyph.getAttribute("data-mp-button-height");
|
|
95
|
+
expect(Number(height)).toBeGreaterThan(0);
|
|
96
|
+
expect(Array.from(glyph.classList).some((c) => /^_w-/.test(c))).toBe(true);
|
|
97
|
+
expect(Array.from(glyph.classList).some((c) => /^_pr-0px|^_pr-0\b/.test(c))).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("an explicit frame is honoured, so the design lint can name it", () => {
|
|
101
|
+
houseRender(
|
|
102
|
+
<>
|
|
103
|
+
<Button outlined icon={Glyph} aria-label="Outlined" />
|
|
104
|
+
<Button circular icon={Glyph} aria-label="Circular" />
|
|
105
|
+
<Button chromeless={false} icon={Glyph} aria-label="Filled" />
|
|
106
|
+
</>,
|
|
107
|
+
"light",
|
|
108
|
+
);
|
|
109
|
+
for (const label of ["Outlined", "Circular", "Filled"])
|
|
110
|
+
expect(screen.getByLabelText(label).hasAttribute("data-mp-icon-button")).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("a selected icon toggle keeps the LC-131 selected fill", () => {
|
|
114
|
+
houseRender(<Button icon={Glyph} aria-label="Shuffle" selected />, "light");
|
|
115
|
+
expect(screen.getByLabelText("Shuffle").getAttribute("data-mp-selected")).toBe("true");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it.each(SCHEMES)("%s: plate=media is the one plated icon button", (scheme) => {
|
|
119
|
+
houseRender(
|
|
120
|
+
<>
|
|
121
|
+
<Button plate="media" icon={Glyph} aria-label="Remove" />
|
|
122
|
+
<Button icon={Glyph} aria-label="More" />
|
|
123
|
+
</>,
|
|
124
|
+
scheme,
|
|
125
|
+
);
|
|
126
|
+
const media = screen.getByLabelText("Remove");
|
|
127
|
+
expect(media.getAttribute("data-mp-icon-button")).toBe("media");
|
|
128
|
+
expect(rest(media, "_bg-")).not.toEqual(rest(screen.getByLabelText("More"), "_bg-"));
|
|
129
|
+
expect(rest(media, "_bg-").join(" ")).not.toMatch(/transparent/);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("a toggle over media shows its state in the glyph, not a selected fill", () => {
|
|
133
|
+
houseRender(<Button plate="media" icon={Glyph} aria-label="Like" aria-pressed />, "light");
|
|
134
|
+
expect(screen.getByLabelText("Like").hasAttribute("data-mp-selected")).toBe(false);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it.each(SCHEMES)(
|
|
138
|
+
"%s: in content with no intent, a bold glyph in the text colour, 24pt or more",
|
|
139
|
+
(scheme) => {
|
|
140
|
+
houseRender(
|
|
141
|
+
<>
|
|
142
|
+
<Button icon={Glyph} aria-label="Neutral" />
|
|
143
|
+
<Button error icon={Glyph} aria-label="Delete" />
|
|
144
|
+
<Surface bar>
|
|
145
|
+
<Button icon={Glyph} aria-label="Bar" />
|
|
146
|
+
</Surface>
|
|
147
|
+
</>,
|
|
148
|
+
scheme,
|
|
149
|
+
);
|
|
150
|
+
const neutral = screen.getByLabelText("Neutral");
|
|
151
|
+
expect(neutral.getAttribute("data-mp-icon-button")).toBe("neutral");
|
|
152
|
+
expect(rest(neutral, "_bg-").join(" ")).not.toMatch(/background|color\d/);
|
|
153
|
+
expect(rest(neutral, "_col-")).not.toEqual(rest(screen.getByLabelText("Bar"), "_col-"));
|
|
154
|
+
expect(glyphOf("Neutral").getAttribute("data-weight")).toBe("bold");
|
|
155
|
+
expect(ICON_BUTTON_NEUTRAL_GLYPH_PX).toBeGreaterThanOrEqual(24);
|
|
156
|
+
expect(Number(glyphOf("Neutral").getAttribute("width"))).toBeGreaterThanOrEqual(
|
|
157
|
+
ICON_BUTTON_NEUTRAL_GLYPH_PX,
|
|
158
|
+
);
|
|
159
|
+
// An intent keeps its own on-page ink and the regular stroke.
|
|
160
|
+
expect(screen.getByLabelText("Delete").getAttribute("data-mp-icon-button")).toBe("glyph");
|
|
161
|
+
expect(glyphOf("Delete").getAttribute("data-weight")).toBe("regular");
|
|
162
|
+
},
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
it("on iOS 26 with the glass module, a bar's icon button floats on Liquid Glass", () => {
|
|
166
|
+
glass.available = true;
|
|
167
|
+
houseRender(
|
|
168
|
+
<>
|
|
169
|
+
<Surface bar>
|
|
170
|
+
<Button icon={Glyph} aria-label="Search" />
|
|
171
|
+
<IconButton inline icon={Glyph} aria-label="InlineInBar" />
|
|
172
|
+
</Surface>
|
|
173
|
+
<Button icon={Glyph} aria-label="Content" />
|
|
174
|
+
</>,
|
|
175
|
+
"light",
|
|
176
|
+
);
|
|
177
|
+
const search = screen.getByLabelText("Search");
|
|
178
|
+
expect(search.getAttribute("data-mp-icon-button")).toBe("glass");
|
|
179
|
+
expect(search.querySelector("[data-glass]")).not.toBeNull();
|
|
180
|
+
expect(glyphOf("Search").getAttribute("data-weight")).toBe("regular");
|
|
181
|
+
// Glass is the bar button; content and inline glyphs never float on it.
|
|
182
|
+
expect(screen.getByLabelText("Content").querySelector("[data-glass]")).toBeNull();
|
|
183
|
+
expect(screen.getByLabelText("InlineInBar").querySelector("[data-glass]")).toBeNull();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("without the glass module (web, Android, older iOS, an older binary) the bar glyph stays bare", () => {
|
|
187
|
+
houseRender(
|
|
188
|
+
<Surface bar>
|
|
189
|
+
<Button icon={Glyph} aria-label="Search" />
|
|
190
|
+
</Surface>,
|
|
191
|
+
"light",
|
|
192
|
+
);
|
|
193
|
+
const search = screen.getByLabelText("Search");
|
|
194
|
+
expect(search.getAttribute("data-mp-icon-button")).toBe("glyph");
|
|
195
|
+
expect(search.querySelector("[data-glass]")).toBeNull();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("IconButton is the same glyph", () => {
|
|
199
|
+
houseRender(
|
|
200
|
+
<Surface bar>
|
|
201
|
+
<IconButton icon={Glyph} aria-label="Named" />
|
|
202
|
+
<Button icon={Glyph} aria-label="Plain" />
|
|
203
|
+
</Surface>,
|
|
204
|
+
"light",
|
|
205
|
+
);
|
|
206
|
+
const named = screen.getByLabelText("Named");
|
|
207
|
+
const plain = screen.getByLabelText("Plain");
|
|
208
|
+
expect(named.getAttribute("data-mp-icon-button")).toBe("glyph");
|
|
209
|
+
expect(rest(named, "_bg-")).toEqual(rest(plain, "_bg-"));
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("a bar glyph carries the weight: 22pt or more, Phosphor regular, in its box", () => {
|
|
213
|
+
houseRender(
|
|
214
|
+
<Surface bar>
|
|
215
|
+
<Button size="$2" icon={Glyph} aria-label="Small" />
|
|
216
|
+
<Button icon={Glyph} aria-label="Default" />
|
|
217
|
+
<IconButton glyphWeight="bold" icon={Glyph} aria-label="Bold" />
|
|
218
|
+
<Button size="$2" icon={Glyph}>
|
|
219
|
+
Label
|
|
220
|
+
</Button>
|
|
221
|
+
</Surface>,
|
|
222
|
+
"light",
|
|
223
|
+
);
|
|
224
|
+
expect(ICON_BUTTON_GLYPH_PX).toBeGreaterThanOrEqual(22);
|
|
225
|
+
expect(Number(glyphOf("Default").getAttribute("width"))).toBeGreaterThanOrEqual(
|
|
226
|
+
ICON_BUTTON_GLYPH_PX,
|
|
227
|
+
);
|
|
228
|
+
for (const label of ["Small", "Default"]) {
|
|
229
|
+
const glyph = glyphOf(label);
|
|
230
|
+
expect(glyph.getAttribute("data-weight")).toBe("regular");
|
|
231
|
+
const box = Number(screen.getByLabelText(label).getAttribute("data-mp-button-height"));
|
|
232
|
+
expect(box).toBeGreaterThanOrEqual(Number(glyph.getAttribute("width")));
|
|
233
|
+
}
|
|
234
|
+
expect(glyphOf("Bold").getAttribute("data-weight")).toBe("bold");
|
|
235
|
+
const labelled = screen.getByText("Label").closest("[role=button]")!;
|
|
236
|
+
const labelGlyph = labelled.querySelector("[data-glyph]")!;
|
|
237
|
+
expect(Number(labelGlyph.getAttribute("width"))).toBeLessThan(ICON_BUTTON_GLYPH_PX);
|
|
238
|
+
expect(labelGlyph.hasAttribute("data-weight")).toBe(false);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("a plate never shrinks its glyph: media and confirm take the bar size", () => {
|
|
242
|
+
houseRender(
|
|
243
|
+
<>
|
|
244
|
+
<Surface bar>
|
|
245
|
+
<Button icon={Glyph} aria-label="Bar" />
|
|
246
|
+
</Surface>
|
|
247
|
+
<Button plate="media" icon={Glyph} aria-label="Remove photo" />
|
|
248
|
+
<Button plate="primary" icon={Glyph} aria-label="Done" />
|
|
249
|
+
</>,
|
|
250
|
+
"light",
|
|
251
|
+
);
|
|
252
|
+
const bar = Number(glyphOf("Bar").getAttribute("width"));
|
|
253
|
+
for (const label of ["Remove photo", "Done"]) {
|
|
254
|
+
expect(Number(glyphOf(label).getAttribute("width"))).toBe(bar);
|
|
255
|
+
expect(glyphOf(label).getAttribute("data-weight")).toBe("regular");
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("an inline glyph is the text's size, 8pt after the value, bold in content", () => {
|
|
260
|
+
houseRender(
|
|
261
|
+
<>
|
|
262
|
+
<IconButton inline icon={Glyph} aria-label="Copy" />
|
|
263
|
+
<IconButton icon={Glyph} aria-label="Bar" />
|
|
264
|
+
</>,
|
|
265
|
+
"light",
|
|
266
|
+
);
|
|
267
|
+
const copy = screen.getByLabelText("Copy");
|
|
268
|
+
expect(copy.getAttribute("data-mp-icon-button")).toBe("inline");
|
|
269
|
+
const size = Number(glyphOf("Copy").getAttribute("width"));
|
|
270
|
+
expect(size).toBeGreaterThan(12);
|
|
271
|
+
expect(size).toBeLessThan(ICON_BUTTON_GLYPH_PX);
|
|
272
|
+
expect(Number(copy.getAttribute("data-mp-button-height"))).toBe(size);
|
|
273
|
+
expect(copy.hasAttribute("data-mp-press-slop")).toBe(true);
|
|
274
|
+
expect(Array.from(copy.classList).some((c) => /^_(mis|ms|ml|marginInlineStart)-/.test(c))).toBe(
|
|
275
|
+
true,
|
|
276
|
+
);
|
|
277
|
+
expect(glyphOf("Copy").getAttribute("data-weight")).toBe("bold");
|
|
278
|
+
});
|
|
279
|
+
});
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { action } from "@multiplatform.one/storybook";
|
|
2
2
|
import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
|
|
3
|
-
import { Activity, Airplay, Download, Trash } from "@tamagui/lucide-icons-2";
|
|
3
|
+
import { Activity, Airplay, Copy, Download, Trash } from "@tamagui/lucide-icons-2";
|
|
4
4
|
import {
|
|
5
5
|
FOCUS_RING_CLIPPED_OFFSET,
|
|
6
6
|
FOCUS_RING_MIN_CONTRAST,
|
|
7
7
|
ensureFocusVisibleRing,
|
|
8
8
|
Paragraph,
|
|
9
|
+
Surface,
|
|
9
10
|
} from "@multiplatform.one/theme";
|
|
10
11
|
import { Button as TamaguiButton, XStack, YStack, useTheme } from "tamagui";
|
|
11
|
-
import { Button, type ButtonProps } from "./index";
|
|
12
|
+
import { Button, IconButton, type ButtonProps } from "./index";
|
|
12
13
|
import { useState } from "react";
|
|
13
14
|
|
|
14
15
|
const pressed = (name: string) => () => action(name)();
|
|
@@ -411,10 +412,65 @@ export const DisabledReasons: Story = {
|
|
|
411
412
|
Publish
|
|
412
413
|
</Button>
|
|
413
414
|
<Button disabled disabledReason="No saved changes" disabledReasonPlacement={placement}>
|
|
414
|
-
Save
|
|
415
|
+
Save draft
|
|
415
416
|
</Button>
|
|
416
417
|
</YStack>
|
|
417
418
|
))}
|
|
418
419
|
</YStack>
|
|
419
420
|
),
|
|
420
421
|
};
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* LC-176 ICON-BUTTON, by context. In a bar the glyph takes the bar tint (on
|
|
425
|
+
* Liquid Glass on iOS 26); in content with no intent it is a bold glyph in the
|
|
426
|
+
* text colour; an intent keeps its ink; a selected toggle keeps LC-131; inline
|
|
427
|
+
* beside a value it is the text's size; over media it rides the one plate.
|
|
428
|
+
*/
|
|
429
|
+
export const IconButtons: Story = {
|
|
430
|
+
render: () => {
|
|
431
|
+
const [on, setOn] = useState(false);
|
|
432
|
+
return (
|
|
433
|
+
<YStack gap="$4" padding="$4" backgroundColor="$background">
|
|
434
|
+
<Surface bar>
|
|
435
|
+
<XStack gap="$1" alignItems="center" data-testid="icon-button-toolbar">
|
|
436
|
+
<IconButton icon={Activity} aria-label="Activity" onPress={pressed("activity")} />
|
|
437
|
+
<IconButton icon={Airplay} aria-label="Cast" onPress={pressed("cast")} />
|
|
438
|
+
<IconButton icon={Download} aria-label="Download" onPress={pressed("download")} />
|
|
439
|
+
<IconButton icon={Download} aria-label="Download (nothing to download)" disabled />
|
|
440
|
+
<IconButton
|
|
441
|
+
icon={Airplay}
|
|
442
|
+
aria-label="Toggle cast"
|
|
443
|
+
selected={on}
|
|
444
|
+
onPress={() => setOn((v) => !v)}
|
|
445
|
+
/>
|
|
446
|
+
</XStack>
|
|
447
|
+
</Surface>
|
|
448
|
+
<XStack gap="$1" alignItems="center" data-testid="icon-button-content">
|
|
449
|
+
<IconButton icon={Download} aria-label="Download" onPress={pressed("download")} />
|
|
450
|
+
<IconButton icon={Trash} error aria-label="Delete" onPress={pressed("delete")} />
|
|
451
|
+
</XStack>
|
|
452
|
+
<XStack alignItems="center" data-testid="icon-button-inline">
|
|
453
|
+
<Paragraph>shc node join</Paragraph>
|
|
454
|
+
<IconButton inline icon={Copy} aria-label="Copy" onPress={pressed("copy")} />
|
|
455
|
+
</XStack>
|
|
456
|
+
<YStack
|
|
457
|
+
position="relative"
|
|
458
|
+
width="$20"
|
|
459
|
+
height="$12"
|
|
460
|
+
backgroundColor="$blue9"
|
|
461
|
+
borderRadius="$4"
|
|
462
|
+
data-testid="icon-button-media"
|
|
463
|
+
>
|
|
464
|
+
<YStack position="absolute" top="$2" right="$2">
|
|
465
|
+
<IconButton
|
|
466
|
+
plate="media"
|
|
467
|
+
icon={Trash}
|
|
468
|
+
aria-label="Remove photo"
|
|
469
|
+
onPress={pressed("remove")}
|
|
470
|
+
/>
|
|
471
|
+
</YStack>
|
|
472
|
+
</YStack>
|
|
473
|
+
</YStack>
|
|
474
|
+
);
|
|
475
|
+
},
|
|
476
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { GlassViewComponent } from "./glass";
|
|
2
|
+
|
|
3
|
+
export type { GlassViewComponent } from "./glass";
|
|
4
|
+
|
|
5
|
+
let cachedGlassView: GlassViewComponent | null | undefined;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* LC-176: expo-glass-effect's `GlassView`, when this binary links its native
|
|
9
|
+
* module and the OS draws Liquid Glass (iOS 26+); Android never links it. The module is probed through
|
|
10
|
+
* `requireOptionalNativeModule` BEFORE the guarded `require`, so an OTA on a
|
|
11
|
+
* binary built without it, or an older iOS, falls back to the bare tinted
|
|
12
|
+
* glyph instead of throwing mid-render (the `nativePickerLoader.ts` contract).
|
|
13
|
+
*/
|
|
14
|
+
export function loadGlassView(): GlassViewComponent | null {
|
|
15
|
+
if (cachedGlassView !== undefined) return cachedGlassView;
|
|
16
|
+
cachedGlassView = null;
|
|
17
|
+
try {
|
|
18
|
+
const core = require("expo-modules-core") as {
|
|
19
|
+
requireOptionalNativeModule?: (moduleName: string) => unknown;
|
|
20
|
+
};
|
|
21
|
+
if (core.requireOptionalNativeModule?.("ExpoGlassEffect") == null) return cachedGlassView;
|
|
22
|
+
const glass = require("expo-glass-effect") as {
|
|
23
|
+
GlassView?: GlassViewComponent;
|
|
24
|
+
isLiquidGlassAvailable?: () => boolean;
|
|
25
|
+
isGlassEffectAPIAvailable?: () => boolean;
|
|
26
|
+
};
|
|
27
|
+
if (
|
|
28
|
+
glass.GlassView &&
|
|
29
|
+
glass.isLiquidGlassAvailable?.() &&
|
|
30
|
+
glass.isGlassEffectAPIAvailable?.()
|
|
31
|
+
) {
|
|
32
|
+
cachedGlassView = glass.GlassView;
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
cachedGlassView = null;
|
|
36
|
+
}
|
|
37
|
+
return cachedGlassView;
|
|
38
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ComponentType } from "react";
|
|
2
|
+
|
|
3
|
+
/** The slice of expo-glass-effect's `GlassView` an icon button draws. */
|
|
4
|
+
export type GlassViewComponent = ComponentType<{
|
|
5
|
+
style?: unknown;
|
|
6
|
+
glassEffectStyle?: "regular" | "clear";
|
|
7
|
+
isInteractive?: boolean;
|
|
8
|
+
pointerEvents?: "none" | "auto" | "box-none" | "box-only";
|
|
9
|
+
}>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* LC-176: the iOS 26 Liquid Glass material an icon button floats on in a bar.
|
|
13
|
+
* Only iOS has it (`glass.native.ts`; the native module is Apple-only, so Android probes null); web, Android and GNOME draw the bare
|
|
14
|
+
* tinted glyph.
|
|
15
|
+
*/
|
|
16
|
+
export function loadGlassView(): GlassViewComponent | null {
|
|
17
|
+
return null;
|
|
18
|
+
}
|