@multiplatform.one/forms 7.5.0 → 7.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Button/index.cjs +6 -10
- package/dist/cjs/Button/index.native.js +6 -10
- package/dist/cjs/Button/index.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.cjs +0 -1
- package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js +0 -1
- package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
- package/dist/cjs/FieldDisplay/index.cjs +2 -1
- package/dist/cjs/FieldDisplay/index.native.js +9 -2
- package/dist/cjs/FieldDisplay/index.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/index.cjs +8 -1
- package/dist/cjs/InputParts/index.cjs +64 -2
- package/dist/cjs/InputParts/index.native.js +70 -4
- package/dist/cjs/InputParts/index.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/BarcodePreview.cjs +15 -9
- package/dist/cjs/fields/Barcode/BarcodePreview.native.js +15 -9
- package/dist/cjs/fields/Barcode/BarcodePreview.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/index.cjs +14 -11
- package/dist/cjs/fields/Combobox/index.native.js +16 -11
- package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/index.cjs +66 -5
- package/dist/cjs/fields/FileUpload/index.native.js +85 -5
- package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/geoValue.cjs +122 -0
- package/dist/cjs/fields/Geolocation/geoValue.native.js +151 -0
- package/dist/cjs/fields/Geolocation/geoValue.native.js.map +1 -0
- package/dist/cjs/fields/Geolocation/index.cjs +16 -29
- package/dist/cjs/fields/Geolocation/index.native.js +16 -29
- package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
- package/dist/cjs/fields/Icon/index.cjs +1 -0
- package/dist/cjs/fields/Icon/index.native.js +1 -0
- package/dist/cjs/fields/Icon/index.native.js.map +1 -1
- package/dist/cjs/fields/Input/index.cjs +175 -95
- package/dist/cjs/fields/Input/index.native.js +83 -4
- package/dist/cjs/fields/Input/index.native.js.map +1 -1
- package/dist/cjs/fields/MentionInput/index.cjs +6 -1
- package/dist/cjs/fields/MentionInput/index.native.js +6 -1
- package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
- package/dist/cjs/fields/OTPInput/index.cjs +7 -2
- package/dist/cjs/fields/OTPInput/index.native.js +7 -2
- package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
- package/dist/cjs/fields/PhoneInput/index.native.js +1 -0
- package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
- package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
- package/dist/cjs/shared/utils.cjs +4 -14
- package/dist/cjs/shared/utils.native.js +6 -14
- package/dist/cjs/shared/utils.native.js.map +1 -1
- package/dist/esm/Button/index.mjs +6 -9
- package/dist/esm/Button/index.mjs.map +1 -1
- package/dist/esm/Button/index.native.js +6 -9
- package/dist/esm/Button/index.native.js.map +1 -1
- package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.mjs +0 -1
- package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.mjs.map +1 -1
- package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js +0 -1
- package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
- package/dist/esm/FieldDisplay/index.mjs +2 -1
- package/dist/esm/FieldDisplay/index.mjs.map +1 -1
- package/dist/esm/FieldDisplay/index.native.js +9 -2
- package/dist/esm/FieldDisplay/index.native.js.map +1 -1
- package/dist/esm/FloatingPanel/index.mjs +8 -1
- package/dist/esm/FloatingPanel/index.mjs.map +1 -1
- package/dist/esm/InputParts/index.mjs +64 -2
- package/dist/esm/InputParts/index.mjs.map +1 -1
- package/dist/esm/InputParts/index.native.js +70 -4
- package/dist/esm/InputParts/index.native.js.map +1 -1
- package/dist/esm/fields/Barcode/BarcodePreview.mjs +15 -9
- package/dist/esm/fields/Barcode/BarcodePreview.mjs.map +1 -1
- package/dist/esm/fields/Barcode/BarcodePreview.native.js +15 -9
- package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
- package/dist/esm/fields/Combobox/index.mjs +14 -11
- package/dist/esm/fields/Combobox/index.mjs.map +1 -1
- package/dist/esm/fields/Combobox/index.native.js +16 -11
- package/dist/esm/fields/Combobox/index.native.js.map +1 -1
- package/dist/esm/fields/FileUpload/index.mjs +66 -5
- package/dist/esm/fields/FileUpload/index.mjs.map +1 -1
- package/dist/esm/fields/FileUpload/index.native.js +85 -5
- package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
- package/dist/esm/fields/Geolocation/geoValue.mjs +95 -0
- package/dist/esm/fields/Geolocation/geoValue.mjs.map +1 -0
- package/dist/esm/fields/Geolocation/geoValue.native.js +121 -0
- package/dist/esm/fields/Geolocation/geoValue.native.js.map +1 -0
- package/dist/esm/fields/Geolocation/index.mjs +15 -28
- package/dist/esm/fields/Geolocation/index.mjs.map +1 -1
- package/dist/esm/fields/Geolocation/index.native.js +15 -28
- package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
- package/dist/esm/fields/Icon/index.mjs +1 -0
- package/dist/esm/fields/Icon/index.mjs.map +1 -1
- package/dist/esm/fields/Icon/index.native.js +1 -0
- package/dist/esm/fields/Icon/index.native.js.map +1 -1
- package/dist/esm/fields/Input/index.mjs +177 -98
- package/dist/esm/fields/Input/index.mjs.map +1 -1
- package/dist/esm/fields/Input/index.native.js +85 -7
- package/dist/esm/fields/Input/index.native.js.map +1 -1
- package/dist/esm/fields/MentionInput/index.mjs +6 -1
- package/dist/esm/fields/MentionInput/index.mjs.map +1 -1
- package/dist/esm/fields/MentionInput/index.native.js +6 -1
- package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
- package/dist/esm/fields/OTPInput/index.mjs +7 -3
- package/dist/esm/fields/OTPInput/index.mjs.map +1 -1
- package/dist/esm/fields/OTPInput/index.native.js +7 -3
- package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
- package/dist/esm/fields/PhoneInput/index.mjs.map +1 -1
- package/dist/esm/fields/PhoneInput/index.native.js +1 -0
- package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
- package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
- package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
- package/dist/esm/shared/utils.mjs +4 -14
- package/dist/esm/shared/utils.mjs.map +1 -1
- package/dist/esm/shared/utils.native.js +6 -14
- package/dist/esm/shared/utils.native.js.map +1 -1
- package/dist/jsx/Button/index.mjs +6 -9
- package/dist/jsx/Button/index.mjs.map +1 -1
- package/dist/jsx/Button/index.native.js +6 -10
- package/dist/jsx/Button/index.native.js.map +1 -1
- package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.mjs +0 -1
- package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.mjs.map +1 -1
- package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.native.js +0 -1
- package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
- package/dist/jsx/FieldDisplay/index.mjs +2 -1
- package/dist/jsx/FieldDisplay/index.mjs.map +1 -1
- package/dist/jsx/FieldDisplay/index.native.js +9 -2
- package/dist/jsx/FieldDisplay/index.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/index.mjs +8 -1
- package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
- package/dist/jsx/InputParts/index.mjs +64 -2
- package/dist/jsx/InputParts/index.mjs.map +1 -1
- package/dist/jsx/InputParts/index.native.js +70 -4
- package/dist/jsx/InputParts/index.native.js.map +1 -1
- package/dist/jsx/fields/Barcode/BarcodePreview.mjs +15 -9
- package/dist/jsx/fields/Barcode/BarcodePreview.mjs.map +1 -1
- package/dist/jsx/fields/Barcode/BarcodePreview.native.js +15 -9
- package/dist/jsx/fields/Barcode/BarcodePreview.native.js.map +1 -1
- package/dist/jsx/fields/Combobox/index.mjs +14 -11
- package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
- package/dist/jsx/fields/Combobox/index.native.js +16 -11
- package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
- package/dist/jsx/fields/FileUpload/index.mjs +66 -5
- package/dist/jsx/fields/FileUpload/index.mjs.map +1 -1
- package/dist/jsx/fields/FileUpload/index.native.js +85 -5
- package/dist/jsx/fields/FileUpload/index.native.js.map +1 -1
- package/dist/jsx/fields/Geolocation/geoValue.mjs +95 -0
- package/dist/jsx/fields/Geolocation/geoValue.mjs.map +1 -0
- package/dist/jsx/fields/Geolocation/geoValue.native.js +151 -0
- package/dist/jsx/fields/Geolocation/geoValue.native.js.map +1 -0
- package/dist/jsx/fields/Geolocation/index.mjs +15 -28
- package/dist/jsx/fields/Geolocation/index.mjs.map +1 -1
- package/dist/jsx/fields/Geolocation/index.native.js +16 -29
- package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
- package/dist/jsx/fields/Icon/index.mjs +1 -0
- package/dist/jsx/fields/Icon/index.mjs.map +1 -1
- package/dist/jsx/fields/Icon/index.native.js +1 -0
- package/dist/jsx/fields/Icon/index.native.js.map +1 -1
- package/dist/jsx/fields/Input/index.mjs +177 -98
- package/dist/jsx/fields/Input/index.mjs.map +1 -1
- package/dist/jsx/fields/Input/index.native.js +83 -4
- package/dist/jsx/fields/Input/index.native.js.map +1 -1
- package/dist/jsx/fields/MentionInput/index.mjs +6 -1
- package/dist/jsx/fields/MentionInput/index.mjs.map +1 -1
- package/dist/jsx/fields/MentionInput/index.native.js +6 -1
- package/dist/jsx/fields/MentionInput/index.native.js.map +1 -1
- package/dist/jsx/fields/OTPInput/index.mjs +7 -3
- package/dist/jsx/fields/OTPInput/index.mjs.map +1 -1
- package/dist/jsx/fields/OTPInput/index.native.js +7 -2
- package/dist/jsx/fields/OTPInput/index.native.js.map +1 -1
- package/dist/jsx/fields/PhoneInput/index.mjs.map +1 -1
- package/dist/jsx/fields/PhoneInput/index.native.js +1 -0
- package/dist/jsx/fields/PhoneInput/index.native.js.map +1 -1
- package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
- package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
- package/dist/jsx/shared/utils.mjs +4 -14
- package/dist/jsx/shared/utils.mjs.map +1 -1
- package/dist/jsx/shared/utils.native.js +6 -14
- package/dist/jsx/shared/utils.native.js.map +1 -1
- package/package.json +7 -7
- package/src/Button/Button.density.spec.tsx +118 -32
- package/src/Button/Button.labelInk.spec.tsx +72 -19
- package/src/Button/Button.lc71.spec.tsx +10 -3
- package/src/Button/Button.stories.tsx +97 -7
- package/src/Button/index.tsx +22 -12
- package/src/ContextualSaveBar/UnsavedChangesDialog.tsx +0 -1
- package/src/FieldDisplay/FieldDisplay.spec.tsx +11 -2
- package/src/FieldDisplay/index.tsx +5 -0
- package/src/FloatingPanel/index.tsx +22 -1
- package/src/FloatingPanel/panelWidthContract.spec.ts +1 -0
- package/src/InputParts/index.tsx +100 -3
- package/src/fields/Barcode/BarcodePreview.spec.tsx +153 -5
- package/src/fields/Barcode/BarcodePreview.stories.tsx +104 -0
- package/src/fields/Barcode/BarcodePreview.tsx +47 -15
- package/src/fields/ColorPicker/PresetSwatches.spec.tsx +71 -0
- package/src/fields/ColorPicker/PresetSwatches.stories.tsx +94 -0
- package/src/fields/Combobox/Combobox.spec.tsx +64 -1
- package/src/fields/Combobox/index.tsx +22 -11
- package/src/fields/FileUpload/FileUpload.spec.tsx +71 -0
- package/src/fields/FileUpload/index.tsx +100 -3
- package/src/fields/Geolocation/Geolocation.spec.tsx +126 -0
- package/src/fields/Geolocation/geoValue.spec.ts +169 -0
- package/src/fields/Geolocation/geoValue.ts +149 -0
- package/src/fields/Geolocation/index.tsx +15 -24
- package/src/fields/Icon/Icon.stories.tsx +1 -1
- package/src/fields/Icon/index.tsx +1 -0
- package/src/fields/Input/index.tsx +180 -81
- package/src/fields/MentionInput/index.tsx +9 -1
- package/src/fields/OTPInput/OtpInput.spec.tsx +36 -4
- package/src/fields/OTPInput/index.tsx +18 -3
- package/src/fields/OTPInput/otpCellHeightTouch.spec.ts +44 -0
- package/src/fields/PhoneInput/index.tsx +1 -0
- package/src/fields/SearchInput/index.tsx +5 -3
- package/src/shared/utils.spec.ts +46 -0
- package/src/shared/utils.ts +31 -16
- package/types/Button/index.d.ts +8 -3
- package/types/Button/index.d.ts.map +1 -1
- package/types/ContextualSaveBar/UnsavedChangesDialog.d.ts.map +1 -1
- package/types/FieldDisplay/index.d.ts.map +1 -1
- package/types/InputParts/index.d.ts +9 -5
- package/types/InputParts/index.d.ts.map +1 -1
- package/types/fields/Barcode/BarcodePreview.d.ts +20 -9
- package/types/fields/Barcode/BarcodePreview.d.ts.map +1 -1
- package/types/fields/Checkbox/index.d.ts +3 -3
- package/types/fields/Combobox/index.d.ts.map +1 -1
- package/types/fields/FileUpload/index.d.ts.map +1 -1
- package/types/fields/Geolocation/geoValue.d.ts +45 -0
- package/types/fields/Geolocation/geoValue.d.ts.map +1 -0
- package/types/fields/Geolocation/index.d.ts.map +1 -1
- package/types/fields/Icon/index.d.ts.map +1 -1
- package/types/fields/Input/index.d.ts +18 -6
- package/types/fields/Input/index.d.ts.map +1 -1
- package/types/fields/MentionInput/index.d.ts.map +1 -1
- package/types/fields/OTPInput/index.d.ts +12 -0
- package/types/fields/OTPInput/index.d.ts.map +1 -1
- package/types/fields/PhoneInput/index.d.ts.map +1 -1
- package/types/fields/RadioGroup/index.d.ts +2 -2
- package/types/fields/SearchInput/index.d.ts.map +1 -1
- package/types/fields/ToggleGroup/index.d.ts +1 -1
- package/types/shared/utils.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","utils_exports","clampRadiusForControl","clampRadiusForLargeComponent","clampRadiusInStateProps","getElevationWrapperProps","getFieldError","getFieldHeight","getOTPCellRadius","mergeFieldHandler","stripRadiusFromStateProps","useFormField","useResolvedValidators","module","exports","import_react","require","import_theme","import_Form","import_validateOn","_type_of","obj","Symbol","constructor","sizeToken","rows","arguments","length","sizeRecipeForToken","String","touch","isTouchSurface","height","clampRadius","radiusToken","maxTokenNum","fallback","startsWith","num","Number","parseInt","slice","OTP_RADIUS_STOPS","keys","borderRadiusMap","otpRadiusStop","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","iterator","_step","next","done","stop","err","return","Error","heightPx","resolveRadiusClass","knobProps","elevationRecipe","_elevationRecipe_hoverKnobProps","_elevationRecipe_pressKnobProps","_elevationRecipe_focusVisibleKnobProps","elevation","hoverKnobProps","pressKnobProps","focusVisibleKnobProps","props","overflow","elevationChrome","hoverStyle","pressStyle","focusVisibleStyle","transition","animation","formContext","useFormContext","resolvedForm","form","resolved","useResolvedKnobs","compact","generatedId","useId","id","field","propError","fieldError","state","meta","errors","defaultIsEmpty","defaultIsEmpty2","v","required","validators","label","isEmpty","validateOn","hasSubmitted","useFormValidate","effective","resolveEffectiveValidateOn","useMemo","requiredValidator","requiredValidator2","param","onSubmit","existingOnSubmit","composedOnSubmit","_existingOnSubmit"],"sources":["../../../src/shared/utils.ts"],"sourcesContent":[null],"mappings":"AAAA,YAAyB;;AAQzB,IAAAA,SAAA,GAAAC,MAAA,CAAAC,cAAA;AAAA,IACEC,gBAAA,GAAAF,MAAA,CAAAG,wBAAA;AAAA,IACAC,iBAAA,GAAAJ,MAAA,CAAAK,mBAAA;AAAA,IACAC,YAAA,GAAAN,MAAA,CAAAO,SAAA,CAAAC,cAAA;AAAA,IACAC,QAAA,GAAAA,CAAAC,MAAA,EAAAC,GAAA;EACA,SAAAC,IAAA,IAAAD,GAAA,EAAAZ,SACK,CAAAW,MAAA,EAAAE,IAAA;IAAAC,GAAA,EAAAF,GAAA,CAAAC,IAAA;IAAAE,UAAA;EAAA;AAEP;AACA,IAAAC,WAAS,GAAAA,CAAAC,EAAA,EAAAC,IAAA,EAAAC,MAA0B,EAAAC,IAAA;EAO5B,IAAAF,IAAS,WAAAA,IAAe,aAAuB,IAAO,OAAWA,IAAA;IACtE,KAAO,IAAAG,GAAA,IAAAhB,iBAA0B,CAAAa,IAAA,GACnC,KAAAX,YAAA,CAAAe,IAAA,CAAAL,EAAA,EAAAI,GAAA,KAAAA,GAAA,KAAAF,MAAA,EAEAnB,SAAS,CAAAiB,EAAA,EACPI,GAAA;MAAAP,GAAA,EACAA,CAAA,KAAAI,IAAA,CAAAG,GACA;MAAAN,UACY,IAAAK,IAAA,GAAAjB,gBAAA,CAAAe,IAAA,EAAAG,GAAA,MAAAD,IAAA,CAAAL;IAAA;EACZ;EACA,OAAIE,EAAA;AACJ;AACE,IAAAM,YAAY,GAAAC,GAAO,IAAAR,WAAS,CAAAhB,SAAY,CAAM,CAAC,GAAG,YAAE;EAAAyB,KAAA;AAAA,IAAAD,GAAA;AACpD,IAAAE,aAAa;AAAkChB,QACjD,CAAAgB,aAAA;EACAC,qBAAO,EAAAA,CAAA,KAAAA,qBAAA;EACTC,4BAAA,EAAAA,CAAA,KAAAA,4BAAA;EAMOC,uBAAS,EAAAA,CAAA,KACdA,uBACA;EAEAC,wBAAmB,EAAAA,CAAA,KAAaA,wBAAiB;EACnDC,aAAA,EAAAA,CAAA,KAAAA,aAAA;EASOC,cAAS,EAAAA,CAAA,KAAAA,cACd;EAGAC,gBAAO,EAAAA,CAAA,KAAYA,gBAAa;EAClCC,iBAAA,EAAAA,CAAA,KAAAA,iBAAA;EAIAC,yBAAyB,EAAAA,CAAA,KAAOA,yBAAoB;EAEpDC,YAAS,EAAAA,CAAA,KAAAA,YAAc;EACrBC,qBAAmB,EAAAA,CAAA,KAAMA;AACzB;AACEC,MAAA,CAAAC,OAAI,GAAShB,YAAA,CAAAG,aAAe;AAA8C,IAC5Ec,YAAA,GAAAC,OAAA;AACA,IAAAC,YAAU,GAAAD,OAAA;AAAA,IACRE,WAAA,GAAAF,OAAA,CAAsB;AAAW,IACnCG,iBAAA,GAAAH,OAAA;AACF,SAAAI,SAAAC,GAAA;EAQO,uBAAS;;EACd,OAAOA,GAAA,WAAAC,MAAmB,oBAAoBD,GAAA,CAAAE,WAAc,KAAAD,MAAW,GAAK,WAAU,OAAAD,GAAA;AACxF;AAUO,SAASd,eAAAiB,SAAA,EACd;EAGA,IAAAC,IAAM,GAAAC,SAAY,CAAAC,MAAA,GAAU,KAAAD,SAAA,iBAAAA,SAAA;EAC5B,OACG,IAAAT,YACA,CAAAW,kBAAgB,EAAAC,MAAA,CAAgBL,SAAA;IAIjCM,KAAA,EAAO,CAAC,GAAAb,YAAA,CAAAc,cAAA;EACV,GAAAC,MAAA,GAAAP,IAAA;AACA;AAAmC,SACjCQ,WAAUA,CAAAC,WAAA,EAAAC,WAAA,EAAAC,QAAA;EAAA,IACV,CAAGF,WAAU,SAAAE,QAAA;EACf,IAAAF,WAAA;EACA,IAAI,OAAAA,WAAgB,iBAAgBA,WAAA,CAAAG,UAAA;IAClC,IAAAC,GAAM,GAAAC,MAAA,CAAAC,QAAa,CAAAN,WAAgB,CAAAO,KAAA;IACrC,OAAAH,GAAA,GAAAH,WAAA,OAAAA,WAAA,KAAAD,WAAA;EACA;EACE,OAAAA,WAAM;AAA6B;AAErC,SAAIhC,qBAAgBA,CAAAgC,WAAA;EAClB,IAAAC,WAAM,GAAAT,SAAA,CAAoBC,MAAA,QAAAD,SAAgB,iBAAAA,SAAA;EAC5C,OAAAO,WAAA,CAAAC,WAAA,EAAAC,WAAA;AACA;AACA,SAAOhC,6BAAA+B,WAAA;EACT,IAAAC,WAAA,GAAAT,SAAA,CAAAC,MAAA,QAAAD,SAAA,iBAAAA,SAAA;EAEO,OAASO,WAAA,CAAAC,WAGE,EAAAC,WAAA;AAChB;AACA,IAAAO,gBAAM,GAAgBlE,MAAM,CAAAmE,IAAA,CAAA1B,YAAQ,CAAA2B,eAAe;AACnD,SAAMC,aAAWA,CAAAX,WAAA,EAAiB;EAClC,IAAAA,WAAM,QAAc,SAAM;EAC1B,IAAAY,yBAAuB;IAAAC,iBAAA;IAAAC,cAAA;EACvB;IACF,SAAAC,SAAA,GAAAP,gBAAA,CAAApB,MAAA,CAAA4B,QAAA,KAAAC,KAAA,IAAAL,yBAAA,IAAAK,KAAA,GAAAF,SAAA,CAAAG,IAAA,IAAAC,IAAA,GAAAP,yBAAA;MAEO,IAASQ,IAAA,GAAAH,KAAA,CACdnD,KAAA;MAGA,IAAMsD,IAAA,KAAApB,WAAmB,IAAMjB,YAAY,CAAA2B,eAChC,CAAAU,IAAM,MAAMpB,WAAK,EAAQ,OAChCoB,IAAA;IACJ;EACF,SAAAC,GAAA;IAEAR,iBAAM,GAAkB;IAEjBC,cAAS,GAAAO,GAAA;EAOd,UAAQ;IACR,IAAM;MAEN,IAAO,CAAAT,yBAAc,IAAAG,SAAA,CAAAO,MAAA;QACfP,SAAA,CAAAO,MAAW;MACf;IACE,UAAM;MAIN,IAAIT,iBAAa;QACf,MAAAC,cAAa;MACf;IACE;EACA;EAIA,UAAAS,KAAA,uBAA4BvB,WAAU,mEAAiB;AAAA;AACzD,SACF1B,iBAAA0B,WAAA,EAAAwB,QAAA;EACA,SAAO,EAAAzC,YAAA,CAAA0C,kBAAyB,EAAU,kBAAS,EAAAd,aAAA,CAAAX,WAAA;IACrDwB;EACF;AAEO;AAKL,SAAOrD,wBAAoBA,CAAAuD,SAAA,EAAAC,eAAA;EACzB,IAACC,+BAAgD,EAAAC,+BAAA,EAAAC,sCAAA;EACjD,IAAAC,SAAU,GAAGL,SAAI,CAAAK,SAAA;EACnB,KAAAA,SAAA,OAAAH,+BAAA,GAAAD,eAAA,CAAAK,cAAA,cAAAJ,+BAAA,uBAAAA,+BAAA,CAAAG,SAAA,QAAAF,+BAAA,GAAAF,eAAA,CAAAM,cAAA,cAAAJ,+BAAA,uBAAAA,+BAAA,CAAAE,SAAA,QAAAD,sCAAA,GAAAH,eAAA,CAAAO,qBAAA,cAAAJ,sCAAA,uBAAAA,sCAAA,CAAAC,SAAA;IACF;EAWO;EACL,IAAII,KAAC;IACLC,QAAQ;IACR,GAAAV,SAAc,CAAAW;EAChB;EAoBA,IAAMV,eAAA,CAAAK,cAAoB;
|
|
1
|
+
{"version":3,"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","utils_exports","clampRadiusForControl","clampRadiusForLargeComponent","clampRadiusInStateProps","getElevationWrapperProps","getFieldError","getFieldHeight","getOTPCellRadius","mergeFieldHandler","stripRadiusFromStateProps","useFormField","useResolvedValidators","module","exports","import_react","require","import_theme","import_Form","import_validateOn","_type_of","obj","Symbol","constructor","sizeToken","rows","arguments","length","sizeRecipeForToken","String","touch","isTouchSurface","height","clampRadius","radiusToken","maxTokenNum","fallback","startsWith","num","Number","parseInt","slice","OTP_RADIUS_STOPS","keys","borderRadiusMap","otpRadiusStop","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","iterator","_step","next","done","stop","err","return","Error","heightPx","resolveRadiusClass","knobProps","elevationRecipe","_elevationRecipe_hoverKnobProps","_elevationRecipe_pressKnobProps","_elevationRecipe_focusVisibleKnobProps","elevation","hoverKnobProps","pressKnobProps","focusVisibleKnobProps","props","overflow","elevationChrome","hoverStyle","pressStyle","focusVisibleStyle","transition","animation","formContext","useFormContext","resolvedForm","form","resolved","useResolvedKnobs","compact","generatedId","useId","id","field","propError","fieldError","state","meta","errors","defaultIsEmpty","defaultIsEmpty2","v","required","validators","label","isEmpty","validateOn","hasSubmitted","useFormValidate","effective","resolveEffectiveValidateOn","useMemo","requiredValidator","requiredValidator2","param","onSubmit","existingOnSubmit","composedOnSubmit","_existingOnSubmit"],"sources":["../../../src/shared/utils.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/forms",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.6.1",
|
|
4
4
|
"description": "Cross-platform form components with URL state management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cross-platform",
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
"perfect-freehand": "^1.2.3",
|
|
71
71
|
"react-native-svg": "15.15.4",
|
|
72
72
|
"tamagui": "2.7.6",
|
|
73
|
-
"@multiplatform.one/
|
|
74
|
-
"@multiplatform.one/
|
|
75
|
-
"@multiplatform.one/
|
|
73
|
+
"@multiplatform.one/router": "7.6.1",
|
|
74
|
+
"@multiplatform.one/table-primitives": "7.6.1",
|
|
75
|
+
"@multiplatform.one/theme": "7.6.1"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@tamagui/build": "2.7.6",
|
|
@@ -95,9 +95,9 @@
|
|
|
95
95
|
"react-i18next": "^16.6.6",
|
|
96
96
|
"react-native-web": "^0.21.2",
|
|
97
97
|
"vitest": "^4.1.5",
|
|
98
|
-
"@multiplatform.one/
|
|
99
|
-
"@multiplatform.one/
|
|
100
|
-
"@multiplatform.one/
|
|
98
|
+
"@multiplatform.one/config": "7.6.1",
|
|
99
|
+
"@multiplatform.one/storybook": "7.6.1",
|
|
100
|
+
"@multiplatform.one/test-utils": "7.6.1"
|
|
101
101
|
},
|
|
102
102
|
"peerDependencies": {
|
|
103
103
|
"expo-haptics": "55.0.17",
|
|
@@ -2,17 +2,25 @@
|
|
|
2
2
|
* @vitest-environment jsdom
|
|
3
3
|
*
|
|
4
4
|
* MPO-42 / LC-76: the density knob and the `compact` PROP must land the
|
|
5
|
-
* SAME padX. Height stays 44 at both stops — density moves
|
|
5
|
+
* SAME padX. Height stays 44 at both stops — density moves space, not size.
|
|
6
|
+
*
|
|
7
|
+
* LC-79 / LC-80: the internals come from the size recipe, so density picks
|
|
8
|
+
* the recipe FAMILY (`control` -> `controlCompact`) and never subtracts a
|
|
9
|
+
* hand-set delta. The delta drifted from the generated table at every token
|
|
10
|
+
* but `$4`, and at `$2` it INVERTED — `max(8, 7 - 2)` painted a compact
|
|
11
|
+
* Button 8px wider than the comfortable 7px one.
|
|
6
12
|
*/
|
|
7
13
|
|
|
8
14
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
9
|
-
import { Preset } from "@multiplatform.one/theme";
|
|
15
|
+
import { Preset, recipeFamilies } from "@multiplatform.one/theme";
|
|
10
16
|
import { cleanup, screen } from "@testing-library/react";
|
|
11
17
|
import { afterEach, describe, expect, it } from "vitest";
|
|
12
|
-
import { Button } from "./index";
|
|
18
|
+
import { Button, buttonDensityFamily, resolveButtonSizeRecipe } from "./index";
|
|
13
19
|
|
|
14
20
|
afterEach(cleanup);
|
|
15
21
|
|
|
22
|
+
const sizes = ["$2", "$3", "$4"] as const;
|
|
23
|
+
|
|
16
24
|
/** Last `_pl-Npx` / `_pr-Npx` class wins (paddingHorizontal expands to both). */
|
|
17
25
|
function paddingPxFromClass(el: HTMLElement): number | null {
|
|
18
26
|
let found: number | null = null;
|
|
@@ -23,56 +31,134 @@ function paddingPxFromClass(el: HTMLElement): number | null {
|
|
|
23
31
|
return found;
|
|
24
32
|
}
|
|
25
33
|
|
|
34
|
+
function gapPxFromClass(el: HTMLElement): number | null {
|
|
35
|
+
for (const c of String(el.className || "").split(/\s+/)) {
|
|
36
|
+
const m = c.match(/^_gap-(\d+)px$/);
|
|
37
|
+
if (m) return Number(m[1]);
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function renderProp(size: (typeof sizes)[number]) {
|
|
43
|
+
renderWithProviders(
|
|
44
|
+
<Button compact size={size} icon={<span>i</span>}>
|
|
45
|
+
Save
|
|
46
|
+
</Button>,
|
|
47
|
+
);
|
|
48
|
+
return screen.getByRole("button");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function renderKnob(size: (typeof sizes)[number]) {
|
|
52
|
+
renderWithProviders(
|
|
53
|
+
<Preset overrides={{ density: "compact" }}>
|
|
54
|
+
<Button size={size} icon={<span>i</span>}>
|
|
55
|
+
Save
|
|
56
|
+
</Button>
|
|
57
|
+
</Preset>,
|
|
58
|
+
);
|
|
59
|
+
return screen.getByRole("button");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function renderComfortable(size: (typeof sizes)[number]) {
|
|
63
|
+
renderWithProviders(
|
|
64
|
+
<Button size={size} icon={<span>i</span>}>
|
|
65
|
+
Save
|
|
66
|
+
</Button>,
|
|
67
|
+
);
|
|
68
|
+
return screen.getByRole("button");
|
|
69
|
+
}
|
|
70
|
+
|
|
26
71
|
describe("Button density knob = compact PROP (MPO-42)", () => {
|
|
27
72
|
it("compact PROP and density:compact knob land the SAME padX", () => {
|
|
28
|
-
|
|
29
|
-
<Button compact size="$4">
|
|
30
|
-
Save
|
|
31
|
-
</Button>,
|
|
32
|
-
);
|
|
33
|
-
const viaProp = screen.getByRole("button");
|
|
73
|
+
const viaProp = renderProp("$4");
|
|
34
74
|
const propPad = paddingPxFromClass(viaProp);
|
|
35
75
|
expect(viaProp.getAttribute("data-mp-density")).toBe("compact");
|
|
36
76
|
expect(propPad).toBe(16);
|
|
37
77
|
cleanup();
|
|
38
78
|
|
|
39
|
-
|
|
40
|
-
<Preset overrides={{ density: "compact" }}>
|
|
41
|
-
<Button size="$4">Save</Button>
|
|
42
|
-
</Preset>,
|
|
43
|
-
);
|
|
44
|
-
const viaKnob = screen.getByRole("button");
|
|
45
|
-
const knobPad = paddingPxFromClass(viaKnob);
|
|
79
|
+
const viaKnob = renderKnob("$4");
|
|
46
80
|
expect(viaKnob.getAttribute("data-mp-density")).toBe("compact");
|
|
47
|
-
expect(
|
|
48
|
-
expect(
|
|
81
|
+
expect(paddingPxFromClass(viaKnob)).toBe(propPad);
|
|
82
|
+
expect(paddingPxFromClass(viaKnob)).toBe(16);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("both channels land the SAME padX at every size step, not just $4", () => {
|
|
86
|
+
for (const size of sizes) {
|
|
87
|
+
const viaProp = paddingPxFromClass(renderProp(size));
|
|
88
|
+
cleanup();
|
|
89
|
+
const viaKnob = paddingPxFromClass(renderKnob(size));
|
|
90
|
+
cleanup();
|
|
91
|
+
expect(viaKnob, `padX at ${size}`).toBe(viaProp);
|
|
92
|
+
}
|
|
49
93
|
});
|
|
50
94
|
|
|
51
95
|
it("height stays 44 at comfortable and compact density stops", () => {
|
|
52
|
-
|
|
53
|
-
const comfortable = screen.getByRole("button");
|
|
96
|
+
const comfortable = renderComfortable("$4");
|
|
54
97
|
expect(comfortable.getAttribute("data-mp-button-height")).toBe("44");
|
|
55
98
|
expect(comfortable.className).toMatch(/_h-44px/);
|
|
56
99
|
expect(paddingPxFromClass(comfortable)).toBe(18);
|
|
57
100
|
cleanup();
|
|
58
101
|
|
|
59
|
-
|
|
60
|
-
<Preset overrides={{ density: "compact" }}>
|
|
61
|
-
<Button size="$4">Save</Button>
|
|
62
|
-
</Preset>,
|
|
63
|
-
);
|
|
64
|
-
const viaKnob = screen.getByRole("button");
|
|
102
|
+
const viaKnob = renderKnob("$4");
|
|
65
103
|
expect(viaKnob.getAttribute("data-mp-button-height")).toBe("44");
|
|
66
104
|
expect(viaKnob.className).toMatch(/_h-44px/);
|
|
67
105
|
cleanup();
|
|
68
106
|
|
|
69
|
-
|
|
70
|
-
<Button compact size="$4">
|
|
71
|
-
Save
|
|
72
|
-
</Button>,
|
|
73
|
-
);
|
|
74
|
-
const viaProp = screen.getByRole("button");
|
|
107
|
+
const viaProp = renderProp("$4");
|
|
75
108
|
expect(viaProp.getAttribute("data-mp-button-height")).toBe("44");
|
|
76
109
|
expect(viaProp.className).toMatch(/_h-44px/);
|
|
77
110
|
});
|
|
111
|
+
|
|
112
|
+
it("density never changes the painted height at any size step (LC-76)", () => {
|
|
113
|
+
for (const size of sizes) {
|
|
114
|
+
const relaxed = renderComfortable(size).getAttribute("data-mp-button-height");
|
|
115
|
+
cleanup();
|
|
116
|
+
const tight = renderKnob(size).getAttribute("data-mp-button-height");
|
|
117
|
+
cleanup();
|
|
118
|
+
expect(tight, `height at ${size}`).toBe(relaxed);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("Button density comes from the recipe family (LC-79 / LC-80)", () => {
|
|
124
|
+
it("density picks the family, it does not subtract from the recipe", () => {
|
|
125
|
+
expect(buttonDensityFamily("control", true)).toBe("controlCompact");
|
|
126
|
+
expect(buttonDensityFamily("control", false)).toBe("control");
|
|
127
|
+
// An explicit controlCompact consumer (Chip) does not tighten twice.
|
|
128
|
+
expect(buttonDensityFamily("controlCompact", true)).toBe("controlCompact");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("compact padX is the generated controlCompact table, at every size", () => {
|
|
132
|
+
for (const size of sizes) {
|
|
133
|
+
const expected = resolveButtonSizeRecipe(size, "controlCompact").paddingHorizontal;
|
|
134
|
+
const viaKnob = paddingPxFromClass(renderKnob(size));
|
|
135
|
+
cleanup();
|
|
136
|
+
expect(viaKnob, `padX at ${size}`).toBe(expected);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("compact is never WIDER than comfortable — the $2 inversion stays fixed", () => {
|
|
141
|
+
for (const size of sizes) {
|
|
142
|
+
const relaxed = paddingPxFromClass(renderComfortable(size)) ?? 0;
|
|
143
|
+
cleanup();
|
|
144
|
+
const tight = paddingPxFromClass(renderKnob(size)) ?? 0;
|
|
145
|
+
cleanup();
|
|
146
|
+
expect(tight, `padX at ${size}`).toBeLessThan(relaxed);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("the inner gap stays the recipe gap — gap == radius at both stops", () => {
|
|
151
|
+
for (const size of sizes) {
|
|
152
|
+
const radius = recipeFamilies.controlCompact.radii[size];
|
|
153
|
+
const relaxed = gapPxFromClass(renderComfortable(size));
|
|
154
|
+
cleanup();
|
|
155
|
+
const tight = gapPxFromClass(renderKnob(size));
|
|
156
|
+
cleanup();
|
|
157
|
+
expect(tight, `gap at ${size}`).toBe(resolveButtonSizeRecipe(size, "controlCompact").gap);
|
|
158
|
+
expect(tight, `gap == radius at ${size}`).toBe(radius);
|
|
159
|
+
expect(relaxed, `comfortable gap at ${size}`).toBe(
|
|
160
|
+
resolveButtonSizeRecipe(size, "control").gap,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
78
164
|
});
|
|
@@ -9,21 +9,20 @@
|
|
|
9
9
|
*
|
|
10
10
|
* jsdom cannot cascade Tamagui CSS, so the DOM arm reads the atomic
|
|
11
11
|
* classes the text node emits (`_col-color11`, `_fow-400`). Contrast is
|
|
12
|
-
* the theme-table arm: intent `$color11`
|
|
13
|
-
* both schemes
|
|
12
|
+
* the theme-table arm: intent `$color11` against EVERY page surface the
|
|
13
|
+
* house theme paints, in both schemes — `$background`/`$color1` (white)
|
|
14
|
+
* and `$color2` (#f9f9fa, what the gallery boards are shot on).
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
import { render, cleanup, screen } from "@testing-library/react";
|
|
17
18
|
import {
|
|
18
19
|
aaTextContrastRatio,
|
|
19
|
-
contrastRatio,
|
|
20
20
|
createDefaultThemeConfig,
|
|
21
21
|
createThemesBuilder,
|
|
22
22
|
defaultAccentTheme,
|
|
23
23
|
defaultBaseTheme,
|
|
24
24
|
defaultBuilderOptions,
|
|
25
|
-
|
|
26
|
-
relativeLuminance,
|
|
25
|
+
measureContrast,
|
|
27
26
|
} from "@multiplatform.one/theme";
|
|
28
27
|
import { afterEach, describe, expect, it } from "vitest";
|
|
29
28
|
import { TamaguiProvider, YStack } from "tamagui";
|
|
@@ -40,6 +39,15 @@ const houseThemes = createThemesBuilder(
|
|
|
40
39
|
|
|
41
40
|
const INTENTS = ["error", "warning", "success"] as const;
|
|
42
41
|
const SCHEMES = ["light", "dark"] as const;
|
|
42
|
+
/**
|
|
43
|
+
* The house theme has THREE page surfaces and they are not interchangeable:
|
|
44
|
+
* `$background` and `$color1` are pure white, `$color2` is #f9f9fa. Every
|
|
45
|
+
* gallery board paints `$color2` (actionFeedbackMain.tsx board root), so a
|
|
46
|
+
* contrast arm that only reads `$background` certifies on a surface the
|
|
47
|
+
* boards never shoot — the same shape of hole as measuring the FRAME
|
|
48
|
+
* instead of the text node. All three are measured here.
|
|
49
|
+
*/
|
|
50
|
+
const WHITE_PAGE_SURFACES = ["background", "color1"] as const;
|
|
43
51
|
|
|
44
52
|
function houseRender(ui: React.ReactElement, theme: "light" | "dark" = "light") {
|
|
45
53
|
return render(
|
|
@@ -53,12 +61,13 @@ function labelNode(text: string): HTMLElement {
|
|
|
53
61
|
return screen.getByText(text);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
/**
|
|
65
|
+
* One implementation of the arithmetic (the point of exporting
|
|
66
|
+
* `measureContrast`), and the REPORTED 2-decimal ratio, so the number a
|
|
67
|
+
* failure prints is the number the verdict used.
|
|
68
|
+
*/
|
|
69
|
+
function pageRatio(ink: string, ground: string, label: string): number {
|
|
70
|
+
return measureContrast({ foreground: ink, background: ground, label }).ratio;
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
describe("Button MPO-40 outlined intent label ink", () => {
|
|
@@ -121,23 +130,67 @@ describe("Button MPO-40 outlined intent label ink", () => {
|
|
|
121
130
|
}
|
|
122
131
|
});
|
|
123
132
|
|
|
124
|
-
it("intent $color11
|
|
133
|
+
it("intent $color11 clears 4.5:1 on the white page surfaces in both schemes; on-fill $color never does", () => {
|
|
125
134
|
for (const scheme of SCHEMES) {
|
|
126
|
-
const ground = houseThemes[scheme].background;
|
|
127
135
|
for (const intent of INTENTS) {
|
|
128
136
|
const ink = houseThemes[`${scheme}_${intent}`].color11;
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
for (const surface of WHITE_PAGE_SURFACES) {
|
|
138
|
+
const ground = houseThemes[scheme][surface];
|
|
139
|
+
const label = `${scheme}_${intent}.color11 ${ink} on ${scheme}.${surface} ${ground}`;
|
|
140
|
+
expect(pageRatio(ink, ground, label), label).toBeGreaterThanOrEqual(aaTextContrastRatio);
|
|
141
|
+
}
|
|
134
142
|
|
|
135
143
|
const onFill = houseThemes[`${scheme}_${intent}_Button`].color;
|
|
144
|
+
const ground = houseThemes[scheme].background;
|
|
136
145
|
expect(
|
|
137
|
-
|
|
146
|
+
pageRatio(onFill, ground, `${scheme}_${intent}_Button.color`),
|
|
138
147
|
`${scheme}_${intent}_Button.color is the on-fill foreground`,
|
|
139
148
|
).toBeLessThan(2);
|
|
140
149
|
}
|
|
141
150
|
}
|
|
142
151
|
});
|
|
152
|
+
|
|
153
|
+
it("dark intent $color11 clears 4.5:1 on the $color2 page surface too", () => {
|
|
154
|
+
for (const intent of INTENTS) {
|
|
155
|
+
const ink = houseThemes[`dark_${intent}`].color11;
|
|
156
|
+
const ground = houseThemes.dark.color2;
|
|
157
|
+
const label = `dark_${intent}.color11 ${ink} on dark.color2 ${ground}`;
|
|
158
|
+
expect(pageRatio(ink, ground, label), label).toBeGreaterThanOrEqual(aaTextContrastRatio);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// PINNED MISS — MPO-40's own secondary finding, still OPEN.
|
|
163
|
+
//
|
|
164
|
+
// Fixing the plumbing (the arm above) was necessary, not sufficient. On
|
|
165
|
+
// $color2 — the surface every gallery board is shot on — light warning
|
|
166
|
+
// and success $color11 are under mpo's own floor, and those are exactly
|
|
167
|
+
// the numbers button-anatomy already prints for its CONTRACT row. The
|
|
168
|
+
// step that would close them is a PALETTE change (Radix yellow-11
|
|
169
|
+
// #9e6c00 / green-11 #218358), owned by the contrast-floor lane, not by
|
|
170
|
+
// the Button. colorRules.ts pins the same warning miss on the intent's
|
|
171
|
+
// own color1 (#fcfcf7, 4.44:1); this pins it on the page ground.
|
|
172
|
+
//
|
|
173
|
+
// These numbers are asserted EXACTLY on purpose. Step the palette and
|
|
174
|
+
// this test fails, which is the reminder to re-measure the board and
|
|
175
|
+
// tick MPO-40's contrast criterion — never a regression to re-baseline.
|
|
176
|
+
it("light warning/success $color11 are STILL under 4.5:1 on the $color2 page surface", () => {
|
|
177
|
+
const ground = houseThemes.light.color2;
|
|
178
|
+
const measured = Object.fromEntries(
|
|
179
|
+
INTENTS.map((intent): [string, number] => [
|
|
180
|
+
intent,
|
|
181
|
+
pageRatio(
|
|
182
|
+
houseThemes[`light_${intent}`].color11,
|
|
183
|
+
ground,
|
|
184
|
+
`light_${intent}.color11 on light.color2`,
|
|
185
|
+
),
|
|
186
|
+
]),
|
|
187
|
+
);
|
|
188
|
+
expect(measured, `light.color2 is ${ground}`).toEqual({
|
|
189
|
+
error: 4.95,
|
|
190
|
+
warning: 4.34,
|
|
191
|
+
success: 4.48,
|
|
192
|
+
});
|
|
193
|
+
expect(measured.warning).toBeLessThan(aaTextContrastRatio);
|
|
194
|
+
expect(measured.success).toBeLessThan(aaTextContrastRatio);
|
|
195
|
+
});
|
|
143
196
|
});
|
|
@@ -6,7 +6,7 @@ import { cleanup, fireEvent, screen } from "@testing-library/react";
|
|
|
6
6
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
7
7
|
import { Preset } from "@multiplatform.one/theme";
|
|
8
8
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
9
|
-
import { Button,
|
|
9
|
+
import { Button, buttonDensityFamily, buttonSizeRecipes, resolveButtonSizeRecipe } from "./index";
|
|
10
10
|
|
|
11
11
|
afterEach(cleanup);
|
|
12
12
|
|
|
@@ -52,8 +52,15 @@ describe("Button size recipes", () => {
|
|
|
52
52
|
|
|
53
53
|
describe("Button density ≠ size", () => {
|
|
54
54
|
it("compact tightens pad without shrinking recipe height", () => {
|
|
55
|
-
|
|
56
|
-
expect(
|
|
55
|
+
// Density picks the FAMILY; it never subtracts from the recipe (LC-79).
|
|
56
|
+
expect(buttonDensityFamily("control", true)).toBe("controlCompact");
|
|
57
|
+
expect(buttonDensityFamily("control", false)).toBe("control");
|
|
58
|
+
expect(resolveButtonSizeRecipe("$4", "controlCompact").paddingHorizontal).toBeLessThan(
|
|
59
|
+
resolveButtonSizeRecipe("$4", "control").paddingHorizontal,
|
|
60
|
+
);
|
|
61
|
+
expect(resolveButtonSizeRecipe("$4", "controlCompact").height).toBe(
|
|
62
|
+
resolveButtonSizeRecipe("$4", "control").height,
|
|
63
|
+
);
|
|
57
64
|
renderWithProviders(
|
|
58
65
|
<Button compact size="$4">
|
|
59
66
|
Save
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { action } from "@multiplatform.one/storybook";
|
|
2
2
|
import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
|
|
3
3
|
import { Activity, Airplay, Download, Trash } from "@tamagui/lucide-icons-2";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
FOCUS_RING_CLIPPED_OFFSET,
|
|
6
|
+
FOCUS_RING_MIN_CONTRAST,
|
|
7
|
+
ensureFocusVisibleRing,
|
|
8
|
+
} from "@multiplatform.one/theme";
|
|
9
|
+
import { Button as TamaguiButton, Paragraph, XStack, YStack, useTheme } from "tamagui";
|
|
5
10
|
import { Button } from "./index";
|
|
6
11
|
|
|
7
12
|
const pressed = (name: string) => () => action(name)();
|
|
@@ -57,11 +62,12 @@ export const Basic: Story = {
|
|
|
57
62
|
options: ["$2", "$3", "$4", "$5", "$6"],
|
|
58
63
|
description: "Tamagui size token",
|
|
59
64
|
},
|
|
60
|
-
variant
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
// The house fill channel is the `outlined` boolean. `variant="outlined"`
|
|
66
|
+
// is raw-tamagui API this component does not read (only the
|
|
67
|
+
// `@multiplatform.one/components` shim maps it), so a `variant` control
|
|
68
|
+
// here drove nothing — MPO-19 X3 measured the board's own "Outlined"
|
|
69
|
+
// specimen rendering as a filled button with a transparent edge.
|
|
70
|
+
outlined: { control: "boolean", description: "Outlined fill style" },
|
|
65
71
|
chromeless: { control: "boolean", description: "Transparent, text-only style" },
|
|
66
72
|
disabled: { control: "boolean", description: "Disable the button" },
|
|
67
73
|
skeleton: { control: "boolean", description: "Show skeleton placeholder" },
|
|
@@ -210,7 +216,7 @@ export const Comparison: Story = {
|
|
|
210
216
|
<Button icon={Activity} onPress={pressed("custom.icon")}>
|
|
211
217
|
With Icon
|
|
212
218
|
</Button>
|
|
213
|
-
<Button
|
|
219
|
+
<Button outlined onPress={pressed("custom.outlined")}>
|
|
214
220
|
Outlined
|
|
215
221
|
</Button>
|
|
216
222
|
<Button disabled disabledReason="Needs a completed draft">
|
|
@@ -241,3 +247,87 @@ export const Comparison: Story = {
|
|
|
241
247
|
</XStack>
|
|
242
248
|
),
|
|
243
249
|
};
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* MPO-41 FOCUS-RING BOARD. Mirrors design-mockups-v3
|
|
253
|
+
* gallery/html/action-and-feedback/button-state-focus.html so the board is
|
|
254
|
+
* re-shot from the repo instead of the retired scratchpad harness
|
|
255
|
+
* (mpo-main-wt @ 8bd3a90da, which no longer exists).
|
|
256
|
+
*
|
|
257
|
+
* `forceStyle="focusVisible"` paints the REAL focus-visible ring. Button reads
|
|
258
|
+
* `pageOutlineColor` outside the intent Theme and spreads it into
|
|
259
|
+
* focusVisibleStyle, so the ring stays neutral on an accent or error fill.
|
|
260
|
+
* Never spread FOCUS_VISIBLE_RING onto an intent Button here: inside the
|
|
261
|
+
* sub-theme `$outlineColor` re-resolves to the fill and measures 1.00:1.
|
|
262
|
+
*
|
|
263
|
+
* Row 3 is the deliberate FOCUS_VISIBLE_RING_INSET specimen (offset -2, the
|
|
264
|
+
* clipped-composite carve-out). On an intent fill it is EXPECTED to miss the
|
|
265
|
+
* 3:1 floor, which `parameters.focusRingBoard.expectedBelowFloor` tells the
|
|
266
|
+
* shooter; the old board reported those as severe findings because the
|
|
267
|
+
* specimen was built from a bare ensureFocusVisibleRing() that now returns 0.
|
|
268
|
+
* The shooter measures the painted composition (computed outline colour and
|
|
269
|
+
* offset, then the surface the band actually lands on), never the declaration.
|
|
270
|
+
*/
|
|
271
|
+
/**
|
|
272
|
+
* The LC-71 §4 clipping carve-out at page scope. A consumer `focusVisibleStyle`
|
|
273
|
+
* REPLACES Button's own ring (it rides the `{...props}` spread), so the inset
|
|
274
|
+
* row has to carry the whole ring itself, and it resolves `$outlineColor` at
|
|
275
|
+
* PAGE scope the way Button does (DG-A11Y-01): inside the intent sub-theme the
|
|
276
|
+
* token derives a ring for the inverted surface, which is the 1.00:1 trap.
|
|
277
|
+
*/
|
|
278
|
+
function InsetRow() {
|
|
279
|
+
const pageOutlineColor = useTheme().outlineColor?.val as string | undefined;
|
|
280
|
+
const inset = ensureFocusVisibleRing({
|
|
281
|
+
outlineOffset: FOCUS_RING_CLIPPED_OFFSET,
|
|
282
|
+
...(pageOutlineColor ? { outlineColor: pageOutlineColor } : undefined),
|
|
283
|
+
});
|
|
284
|
+
return (
|
|
285
|
+
<XStack gap="$3" alignItems="center" flexWrap="wrap">
|
|
286
|
+
<Button testID="inset-accent" accent forceStyle="focusVisible" focusVisibleStyle={inset}>
|
|
287
|
+
Accent, offset -2
|
|
288
|
+
</Button>
|
|
289
|
+
<Button testID="inset-error" error forceStyle="focusVisible" focusVisibleStyle={inset}>
|
|
290
|
+
Error, offset -2
|
|
291
|
+
</Button>
|
|
292
|
+
</XStack>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export const StateFocus: Story = {
|
|
297
|
+
name: "State: focus (MPO-41 board)",
|
|
298
|
+
parameters: {
|
|
299
|
+
focusRingBoard: {
|
|
300
|
+
floor: FOCUS_RING_MIN_CONTRAST,
|
|
301
|
+
specimens: ["focus-default", "focus-accent", "focus-error", "inset-accent", "inset-error"],
|
|
302
|
+
expectedBelowFloor: ["inset-accent", "inset-error"],
|
|
303
|
+
},
|
|
304
|
+
docs: {
|
|
305
|
+
description: {
|
|
306
|
+
story:
|
|
307
|
+
'MPO-41 board. Rings forced on with forceStyle="focusVisible" so light and dark ' +
|
|
308
|
+
"shoot in one pass. Rows: rest vs focus on the neutral fill; focus on accent and " +
|
|
309
|
+
"error (offset 0, band on the page ground, must be >= 3:1); the inset carve-out " +
|
|
310
|
+
"(offset -2, band on the control's own fill, expected below the floor on intent).",
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
render: () => (
|
|
315
|
+
<YStack testID="focus-ring-board" gap="$4" padding="$4" backgroundColor="$background">
|
|
316
|
+
<XStack gap="$3" alignItems="center" flexWrap="wrap">
|
|
317
|
+
<Button testID="rest">Rest</Button>
|
|
318
|
+
<Button testID="focus-default" forceStyle="focusVisible">
|
|
319
|
+
Focus
|
|
320
|
+
</Button>
|
|
321
|
+
</XStack>
|
|
322
|
+
<XStack gap="$3" alignItems="center" flexWrap="wrap">
|
|
323
|
+
<Button testID="focus-accent" accent forceStyle="focusVisible">
|
|
324
|
+
Accent focus
|
|
325
|
+
</Button>
|
|
326
|
+
<Button testID="focus-error" error forceStyle="focusVisible">
|
|
327
|
+
Error focus
|
|
328
|
+
</Button>
|
|
329
|
+
</XStack>
|
|
330
|
+
<InsetRow />
|
|
331
|
+
</YStack>
|
|
332
|
+
),
|
|
333
|
+
};
|
package/src/Button/index.tsx
CHANGED
|
@@ -76,13 +76,18 @@ export function resolveButtonSizeRecipe(
|
|
|
76
76
|
return sizeRecipeForToken(size == null ? "$true" : String(size), { family });
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Density selects the recipe FAMILY, it does not subtract from the recipe
|
|
81
|
+
* (LC-79 / LC-80): control -> controlCompact, same heights, tighter ratios.
|
|
82
|
+
* A hand-set delta is a second density writer and it drifts from the
|
|
83
|
+
* generated table at every token but `$4` — it inverted at `$2`, where
|
|
84
|
+
* `max(8, 7 - 2)` painted a compact Button WIDER than a comfortable one.
|
|
85
|
+
*/
|
|
86
|
+
export function buttonDensityFamily(
|
|
87
|
+
family: RecipeFamilyName,
|
|
88
|
+
densityTight: boolean,
|
|
89
|
+
): RecipeFamilyName {
|
|
90
|
+
return densityTight ? "controlCompact" : family;
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
/**
|
|
@@ -416,9 +421,11 @@ export function Button({
|
|
|
416
421
|
(warning && "warning") ||
|
|
417
422
|
(success && "success") ||
|
|
418
423
|
undefined;
|
|
419
|
-
// compact is density
|
|
424
|
+
// compact is density, not a size step — do not pass it through
|
|
420
425
|
// useResolvedKnobs (size stays on the size axis; LC-76). The PROP and the
|
|
421
|
-
// density knob
|
|
426
|
+
// density knob share one channel: both pick the recipe FAMILY, the same
|
|
427
|
+
// way resolveKnobs picks it for every other control, so both land the
|
|
428
|
+
// same padX and the internals stay recipe-generated (LC-75 / LC-79).
|
|
422
429
|
const { knobProps, control, text, disabledState } = useResolvedKnobs({
|
|
423
430
|
intent,
|
|
424
431
|
component: "Button",
|
|
@@ -430,10 +437,13 @@ export function Button({
|
|
|
430
437
|
const grouped = useControlGrouped();
|
|
431
438
|
const sizeProp = (props as { size?: SizeTokens | number }).size;
|
|
432
439
|
const resolvedSize = sizeProp ?? knobProps.sizeToken;
|
|
433
|
-
const recipe = resolveButtonSizeRecipe(resolvedSize, recipeFamily);
|
|
434
440
|
const densityTight = compact !== undefined ? compact === true : knobProps.density === "compact";
|
|
435
|
-
const
|
|
436
|
-
|
|
441
|
+
const recipe = resolveButtonSizeRecipe(
|
|
442
|
+
resolvedSize,
|
|
443
|
+
buttonDensityFamily(recipeFamily, densityTight),
|
|
444
|
+
);
|
|
445
|
+
const padX = recipe.paddingHorizontal;
|
|
446
|
+
const innerGap = recipe.gap;
|
|
437
447
|
if (skeleton) {
|
|
438
448
|
return (
|
|
439
449
|
<View
|