Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client

Merge with social-app upstream again

xan.lol 8c3553cd 3814f6b4

verified
+2960 -3117
-127
.eslintrc.js
··· 1 - module.exports = { 2 - root: true, 3 - extends: [ 4 - '@react-native', 5 - 'plugin:react/recommended', 6 - 'plugin:react/jsx-runtime', 7 - 'plugin:react-native-a11y/ios', 8 - 'prettier', 9 - ], 10 - parser: '@typescript-eslint/parser', 11 - plugins: [ 12 - '@typescript-eslint', 13 - 'react', 14 - 'lingui', 15 - 'simple-import-sort', 16 - 'bsky-internal', 17 - 'eslint-plugin-react-compiler', 18 - 'import', 19 - ], 20 - rules: { 21 - 'react/no-unescaped-entities': 0, 22 - 'react/prop-types': 0, 23 - 'react-native/no-inline-styles': 0, 24 - 'bsky-internal/avoid-unwrapped-text': [ 25 - 'error', 26 - { 27 - impliedTextComponents: [ 28 - 'H1', 29 - 'H2', 30 - 'H3', 31 - 'H4', 32 - 'H5', 33 - 'H6', 34 - 'P', 35 - 'Admonition', 36 - 'Admonition.Admonition', 37 - 'Toast.Action', 38 - 'toast.Action', 39 - 'AgeAssuranceAdmonition', 40 - 'Span', 41 - 'StackedButton', 42 - ], 43 - impliedTextProps: [], 44 - suggestedTextWrappers: { 45 - Button: 'ButtonText', 46 - 'ToggleButton.Button': 'ToggleButton.ButtonText', 47 - 'SegmentedControl.Item': 'SegmentedControl.ItemText', 48 - }, 49 - }, 50 - ], 51 - 'bsky-internal/use-exact-imports': 'error', 52 - 'bsky-internal/use-typed-gates': 'error', 53 - 'bsky-internal/use-prefixed-imports': 'error', 54 - 'simple-import-sort/imports': [ 55 - 'error', 56 - { 57 - groups: [ 58 - // Side effect imports. 59 - ['^\\u0000'], 60 - // Node.js builtins prefixed with `node:`. 61 - ['^node:'], 62 - // Packages. 63 - // Things that start with a letter (or digit or underscore), or `@` followed by a letter. 64 - // React/React Native priortized, followed by expo 65 - // Followed by all packages excluding unprefixed relative ones 66 - [ 67 - '^(react\\/(.*)$)|^(react$)|^(react-native(.*)$)', 68 - '^(expo(.*)$)|^(expo$)', 69 - '^(?!(?:alf|components|lib|locale|logger|platform|screens|state|view)(?:$|\\/))@?\\w', 70 - ], 71 - // Relative imports. 72 - // Ideally, anything that starts with a dot or # 73 - // due to unprefixed relative imports being used, we whitelist the relative paths we use 74 - // (?:$|\\/) matches end of string or / 75 - [ 76 - '^(?:#\\/)?(?:lib|state|logger|platform|locale)(?:$|\\/)', 77 - '^(?:#\\/)?view(?:$|\\/)', 78 - '^(?:#\\/)?screens(?:$|\\/)', 79 - '^(?:#\\/)?alf(?:$|\\/)', 80 - '^(?:#\\/)?components(?:$|\\/)', 81 - '^#\\/', 82 - '^\\.', 83 - ], 84 - // anything else - hopefully we don't have any of these 85 - ['^'], 86 - ], 87 - }, 88 - ], 89 - 'simple-import-sort/exports': 'error', 90 - 'react-compiler/react-compiler': 'warn', 91 - 'no-unused-vars': 'off', 92 - '@typescript-eslint/no-unused-vars': [ 93 - 'error', 94 - {argsIgnorePattern: '^_', varsIgnorePattern: '^_.+'}, 95 - ], 96 - '@typescript-eslint/consistent-type-imports': [ 97 - 'warn', 98 - {prefer: 'type-imports', fixStyle: 'inline-type-imports'}, 99 - ], 100 - 'import/consistent-type-specifier-style': ['warn', 'prefer-inline'], 101 - }, 102 - ignorePatterns: [ 103 - '**/__mocks__/*.ts', 104 - 'src/platform/polyfills.ts', 105 - 'src/third-party', 106 - 'ios', 107 - 'android', 108 - 'coverage', 109 - '*.lock', 110 - '.husky', 111 - 'patches', 112 - '*.html', 113 - 'bskyweb', 114 - 'bskyembed', 115 - 'src/locale/locales/_build/', 116 - 'src/locale/locales/**/*.js', 117 - '*.e2e.ts', 118 - '*.e2e.tsx', 119 - ], 120 - settings: { 121 - componentWrapperFunctions: ['observer'], 122 - }, 123 - parserOptions: { 124 - sourceType: 'module', 125 - ecmaVersion: 'latest', 126 - }, 127 - }
+2 -2
CLAUDE.md
··· 439 439 440 440 Platform detection: 441 441 ```tsx 442 - import {isWeb, isNative, isIOS, isAndroid} from '#/platform/detection' 442 + import {IS_WEB, IS_NATIVE, IS_IOS, IS_ANDROID} from '#/env' 443 443 444 - if (isNative) { 444 + if (IS_NATIVE) { 445 445 // Native-specific logic 446 446 } 447 447 ```
-22
bskyembed/.eslintrc.cjs
··· 1 - module.exports = { 2 - root: true, 3 - parser: '@typescript-eslint/parser', 4 - plugins: ['@typescript-eslint', 'simple-import-sort'], 5 - extends: [ 6 - 'eslint:recommended', 7 - 'preact', 8 - 'plugin:@typescript-eslint/recommended', 9 - 'plugin:@typescript-eslint/recommended-requiring-type-checking', 10 - ], 11 - rules: { 12 - 'simple-import-sort/imports': 'warn', 13 - 'simple-import-sort/exports': 'warn', 14 - 'no-else-return': 'off', 15 - }, 16 - parserOptions: { 17 - sourceType: 'module', 18 - ecmaVersion: 'latest', 19 - project: ['./tsconfig.json'], 20 - tsconfigRootDir: __dirname, 21 - }, 22 - }
+52
bskyembed/eslint.config.mjs
··· 1 + // @ts-check 2 + import js from '@eslint/js' 3 + import tseslint from 'typescript-eslint' 4 + import simpleImportSort from 'eslint-plugin-simple-import-sort' 5 + import globals from 'globals' 6 + 7 + export default tseslint.config( 8 + // Global ignores 9 + { 10 + ignores: ['dist/**', 'node_modules/**'], 11 + }, 12 + 13 + // Base JS recommended rules 14 + js.configs.recommended, 15 + 16 + // TypeScript rules with type checking 17 + ...tseslint.configs.recommendedTypeChecked, 18 + 19 + // Main configuration 20 + { 21 + files: ['**/*.{js,jsx,ts,tsx}'], 22 + plugins: { 23 + 'simple-import-sort': simpleImportSort, 24 + }, 25 + languageOptions: { 26 + ecmaVersion: 'latest', 27 + sourceType: 'module', 28 + globals: { 29 + ...globals.browser, 30 + }, 31 + parserOptions: { 32 + projectService: true, 33 + tsconfigRootDir: import.meta.dirname, 34 + }, 35 + }, 36 + rules: { 37 + 'simple-import-sort/imports': 'warn', 38 + 'simple-import-sort/exports': 'warn', 39 + 'no-else-return': 'off', 40 + '@typescript-eslint/no-require-imports': 'off', 41 + '@typescript-eslint/no-unused-vars': [ 42 + 'error', 43 + { 44 + argsIgnorePattern: '^_', 45 + varsIgnorePattern: '^_.+', 46 + caughtErrors: 'none', 47 + ignoreRestSiblings: true, 48 + }, 49 + ], 50 + }, 51 + }, 52 + )
+6 -4
bskyembed/package.json
··· 7 7 "dev-snippet": "tsc --project tsconfig.snippet.json && serve -s dist -p 3000 -n", 8 8 "build": "tsc && vite build", 9 9 "build-snippet": "tsc --project tsconfig.snippet.json", 10 - "lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src", 10 + "lint": "eslint --cache src", 11 11 "typecheck": "tsc --noEmit" 12 12 }, 13 13 "dependencies": { ··· 17 17 "devDependencies": { 18 18 "@preact/preset-vite": "^2.10.2", 19 19 "@vitejs/plugin-legacy": "^7.0.0", 20 + "@eslint/js": "^9.18.0", 20 21 "autoprefixer": "^10.4.19", 21 - "eslint": "^8.19.0", 22 - "eslint-config-preact": "^1.3.0", 23 - "eslint-plugin-simple-import-sort": "^12.0.0", 22 + "eslint": "^9.18.0", 23 + "eslint-plugin-simple-import-sort": "^12.1.1", 24 + "globals": "^15.14.0", 24 25 "postcss": "^8.4.38", 26 + "typescript-eslint": "^8.20.0", 25 27 "serve": "^14.2.5", 26 28 "tailwindcss": "^3.4.3", 27 29 "terser": "^5.43.1",
+303 -1345
bskyembed/yarn.lock
··· 68 68 "@atproto/lexicon" "^0.4.12" 69 69 zod "^3.23.8" 70 70 71 - "@babel/code-frame@^7.24.2", "@babel/code-frame@^7.27.1": 71 + "@babel/code-frame@^7.27.1": 72 72 version "7.27.1" 73 73 resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" 74 74 integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== ··· 82 82 resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790" 83 83 integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw== 84 84 85 - "@babel/core@^7.13.16": 86 - version "7.24.4" 87 - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.4.tgz#1f758428e88e0d8c563874741bc4ffc4f71a4717" 88 - integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== 89 - dependencies: 90 - "@ampproject/remapping" "^2.2.0" 91 - "@babel/code-frame" "^7.24.2" 92 - "@babel/generator" "^7.24.4" 93 - "@babel/helper-compilation-targets" "^7.23.6" 94 - "@babel/helper-module-transforms" "^7.23.3" 95 - "@babel/helpers" "^7.24.4" 96 - "@babel/parser" "^7.24.4" 97 - "@babel/template" "^7.24.0" 98 - "@babel/traverse" "^7.24.1" 99 - "@babel/types" "^7.24.0" 100 - convert-source-map "^2.0.0" 101 - debug "^4.1.0" 102 - gensync "^1.0.0-beta.2" 103 - json5 "^2.2.3" 104 - semver "^6.3.1" 105 - 106 85 "@babel/core@^7.22.1", "@babel/core@^7.27.4": 107 86 version "7.28.0" 108 87 resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4" ··· 124 103 json5 "^2.2.3" 125 104 semver "^6.3.1" 126 105 127 - "@babel/eslint-parser@^7.13.14": 128 - version "7.24.1" 129 - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz#e27eee93ed1d271637165ef3a86e2b9332395c32" 130 - integrity sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ== 131 - dependencies: 132 - "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" 133 - eslint-visitor-keys "^2.1.0" 134 - semver "^6.3.1" 135 - 136 - "@babel/generator@^7.24.4", "@babel/generator@^7.28.0": 106 + "@babel/generator@^7.28.0": 137 107 version "7.28.0" 138 108 resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2" 139 109 integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg== ··· 151 121 dependencies: 152 122 "@babel/types" "^7.27.3" 153 123 154 - "@babel/helper-compilation-targets@^7.23.6", "@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2": 124 + "@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2": 155 125 version "7.27.2" 156 126 resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" 157 127 integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== ··· 216 186 "@babel/traverse" "^7.27.1" 217 187 "@babel/types" "^7.27.1" 218 188 219 - "@babel/helper-module-transforms@^7.23.3", "@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.27.3": 189 + "@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.27.3": 220 190 version "7.27.3" 221 191 resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02" 222 192 integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg== ··· 232 202 dependencies: 233 203 "@babel/types" "^7.27.1" 234 204 235 - "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.27.1": 205 + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.27.1": 236 206 version "7.27.1" 237 207 resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" 238 208 integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== 239 209 240 - "@babel/helper-plugin-utils@^7.12.13": 241 - version "7.24.0" 242 - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" 243 - integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== 244 - 245 210 "@babel/helper-remap-async-to-generator@^7.27.1": 246 211 version "7.27.1" 247 212 resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz#4601d5c7ce2eb2aea58328d43725523fcd362ce6" ··· 292 257 "@babel/traverse" "^7.27.1" 293 258 "@babel/types" "^7.27.1" 294 259 295 - "@babel/helpers@^7.24.4", "@babel/helpers@^7.27.6": 260 + "@babel/helpers@^7.27.6": 296 261 version "7.27.6" 297 262 resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c" 298 263 integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug== ··· 300 265 "@babel/template" "^7.27.2" 301 266 "@babel/types" "^7.27.6" 302 267 303 - "@babel/parser@^7.24.4", "@babel/parser@^7.27.2", "@babel/parser@^7.28.0": 268 + "@babel/parser@^7.27.2", "@babel/parser@^7.28.0": 304 269 version "7.28.0" 305 270 resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" 306 271 integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== ··· 351 316 resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" 352 317 integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== 353 318 354 - "@babel/plugin-syntax-class-properties@^7.12.13": 355 - version "7.12.13" 356 - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" 357 - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== 358 - dependencies: 359 - "@babel/helper-plugin-utils" "^7.12.13" 360 - 361 - "@babel/plugin-syntax-decorators@^7.12.13": 362 - version "7.24.1" 363 - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.1.tgz#71d9ad06063a6ac5430db126b5df48c70ee885fa" 364 - integrity sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw== 365 - dependencies: 366 - "@babel/helper-plugin-utils" "^7.24.0" 367 - 368 319 "@babel/plugin-syntax-import-assertions@^7.27.1": 369 320 version "7.27.1" 370 321 resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz#88894aefd2b03b5ee6ad1562a7c8e1587496aecd" ··· 378 329 integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== 379 330 dependencies: 380 331 "@babel/helper-plugin-utils" "^7.27.1" 381 - 382 - "@babel/plugin-syntax-jsx@^7.12.13": 383 - version "7.24.1" 384 - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" 385 - integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== 386 - dependencies: 387 - "@babel/helper-plugin-utils" "^7.24.0" 388 332 389 333 "@babel/plugin-syntax-jsx@^7.27.1": 390 334 version "7.27.1" ··· 901 845 "@babel/types" "^7.4.4" 902 846 esutils "^2.0.2" 903 847 904 - "@babel/template@^7.24.0", "@babel/template@^7.27.1", "@babel/template@^7.27.2": 848 + "@babel/template@^7.27.1", "@babel/template@^7.27.2": 905 849 version "7.27.2" 906 850 resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" 907 851 integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== ··· 910 854 "@babel/parser" "^7.27.2" 911 855 "@babel/types" "^7.27.1" 912 856 913 - "@babel/traverse@^7.24.1", "@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": 857 + "@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": 914 858 version "7.28.0" 915 859 resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b" 916 860 integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg== ··· 923 867 "@babel/types" "^7.28.0" 924 868 debug "^4.3.1" 925 869 926 - "@babel/types@^7.24.0", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.27.6", "@babel/types@^7.28.0", "@babel/types@^7.4.4": 870 + "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.27.6", "@babel/types@^7.28.0", "@babel/types@^7.4.4": 927 871 version "7.28.1" 928 872 resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.1.tgz#2aaf3c10b31ba03a77ac84f52b3912a0edef4cf9" 929 873 integrity sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ== ··· 1061 1005 resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz#4276edd5c105bc28b11c6a1f76fb9d29d1bd25c1" 1062 1006 integrity sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA== 1063 1007 1064 - "@eslint-community/eslint-utils@^4.2.0": 1065 - version "4.4.0" 1066 - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" 1067 - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== 1008 + "@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": 1009 + version "4.9.1" 1010 + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" 1011 + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== 1068 1012 dependencies: 1069 - eslint-visitor-keys "^3.3.0" 1013 + eslint-visitor-keys "^3.4.3" 1070 1014 1071 - "@eslint-community/regexpp@^4.6.1": 1072 - version "4.10.0" 1073 - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" 1074 - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== 1015 + "@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2": 1016 + version "4.12.2" 1017 + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" 1018 + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== 1075 1019 1076 - "@eslint/eslintrc@^2.1.4": 1077 - version "2.1.4" 1078 - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" 1079 - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== 1020 + "@eslint/config-array@^0.21.1": 1021 + version "0.21.1" 1022 + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713" 1023 + integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== 1024 + dependencies: 1025 + "@eslint/object-schema" "^2.1.7" 1026 + debug "^4.3.1" 1027 + minimatch "^3.1.2" 1028 + 1029 + "@eslint/config-helpers@^0.4.2": 1030 + version "0.4.2" 1031 + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" 1032 + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== 1033 + dependencies: 1034 + "@eslint/core" "^0.17.0" 1035 + 1036 + "@eslint/core@^0.17.0": 1037 + version "0.17.0" 1038 + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" 1039 + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== 1040 + dependencies: 1041 + "@types/json-schema" "^7.0.15" 1042 + 1043 + "@eslint/eslintrc@^3.3.1": 1044 + version "3.3.3" 1045 + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.3.tgz#26393a0806501b5e2b6a43aa588a4d8df67880ac" 1046 + integrity sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ== 1080 1047 dependencies: 1081 1048 ajv "^6.12.4" 1082 1049 debug "^4.3.2" 1083 - espree "^9.6.0" 1084 - globals "^13.19.0" 1050 + espree "^10.0.1" 1051 + globals "^14.0.0" 1085 1052 ignore "^5.2.0" 1086 1053 import-fresh "^3.2.1" 1087 - js-yaml "^4.1.0" 1054 + js-yaml "^4.1.1" 1088 1055 minimatch "^3.1.2" 1089 1056 strip-json-comments "^3.1.1" 1090 1057 1091 - "@eslint/js@8.57.0": 1092 - version "8.57.0" 1093 - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" 1094 - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== 1058 + "@eslint/js@9.39.2", "@eslint/js@^9.18.0": 1059 + version "9.39.2" 1060 + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.2.tgz#2d4b8ec4c3ea13c1b3748e0c97ecd766bdd80599" 1061 + integrity sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA== 1062 + 1063 + "@eslint/object-schema@^2.1.7": 1064 + version "2.1.7" 1065 + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" 1066 + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== 1067 + 1068 + "@eslint/plugin-kit@^0.4.1": 1069 + version "0.4.1" 1070 + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" 1071 + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== 1072 + dependencies: 1073 + "@eslint/core" "^0.17.0" 1074 + levn "^0.4.1" 1075 + 1076 + "@humanfs/core@^0.19.1": 1077 + version "0.19.1" 1078 + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" 1079 + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== 1095 1080 1096 - "@humanwhocodes/config-array@^0.11.14": 1097 - version "0.11.14" 1098 - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" 1099 - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== 1081 + "@humanfs/node@^0.16.6": 1082 + version "0.16.7" 1083 + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.7.tgz#822cb7b3a12c5a240a24f621b5a2413e27a45f26" 1084 + integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== 1100 1085 dependencies: 1101 - "@humanwhocodes/object-schema" "^2.0.2" 1102 - debug "^4.3.1" 1103 - minimatch "^3.0.5" 1086 + "@humanfs/core" "^0.19.1" 1087 + "@humanwhocodes/retry" "^0.4.0" 1104 1088 1105 1089 "@humanwhocodes/module-importer@^1.0.1": 1106 1090 version "1.0.1" 1107 1091 resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" 1108 1092 integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== 1109 1093 1110 - "@humanwhocodes/object-schema@^2.0.2": 1111 - version "2.0.3" 1112 - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" 1113 - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== 1094 + "@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": 1095 + version "0.4.3" 1096 + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" 1097 + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== 1114 1098 1115 1099 "@isaacs/cliui@^8.0.2": 1116 1100 version "8.0.2" ··· 1172 1156 "@jridgewell/resolve-uri" "^3.1.0" 1173 1157 "@jridgewell/sourcemap-codec" "^1.4.14" 1174 1158 1175 - "@mdn/browser-compat-data@^5.2.34", "@mdn/browser-compat-data@^5.3.13": 1176 - version "5.5.19" 1177 - resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-5.5.19.tgz#5c661edd669ee990dbdf2e1a8ee3c9c1c6fa7117" 1178 - integrity sha512-ntKBZtwWCy4XvJosdTJKqIMdmzgbxjopfoiMxgpzsml3dXqA7MIHCE/amidfQc06a6KvmMrpiVuYHIBt2feDog== 1179 - 1180 - "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": 1181 - version "5.1.1-v1" 1182 - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" 1183 - integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== 1184 - dependencies: 1185 - eslint-scope "5.1.1" 1186 - 1187 1159 "@nodelib/fs.scandir@2.1.5": 1188 1160 version "2.1.5" 1189 1161 resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" ··· 1197 1169 resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 1198 1170 integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 1199 1171 1200 - "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": 1172 + "@nodelib/fs.walk@^1.2.3": 1201 1173 version "1.2.8" 1202 1174 resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 1203 1175 integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== ··· 1358 1330 resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.0.tgz#0a7eecae41f463d6591c8fecd7a5c5087345ee36" 1359 1331 integrity sha512-SRf1cytG7wqcHVLrBc9VtPK4pU5wxiB/lNIkNmW2ApKXIg+RpqwHfsaEK+e7eH4A1BpI6BX/aBWXxZCIrJg3uA== 1360 1332 1361 - "@types/estree@1.0.8": 1333 + "@types/estree@1.0.8", "@types/estree@^1.0.6": 1362 1334 version "1.0.8" 1363 1335 resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" 1364 1336 integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== 1365 1337 1366 - "@types/json-schema@^7.0.9": 1338 + "@types/json-schema@^7.0.15": 1367 1339 version "7.0.15" 1368 1340 resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" 1369 1341 integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== 1370 1342 1371 - "@types/semver@^7.3.12": 1372 - version "7.5.8" 1373 - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" 1374 - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== 1343 + "@typescript-eslint/eslint-plugin@8.52.0": 1344 + version "8.52.0" 1345 + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz#9a9f1d2ee974ed77a8b1bda94e77123f697ee8b4" 1346 + integrity sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q== 1347 + dependencies: 1348 + "@eslint-community/regexpp" "^4.12.2" 1349 + "@typescript-eslint/scope-manager" "8.52.0" 1350 + "@typescript-eslint/type-utils" "8.52.0" 1351 + "@typescript-eslint/utils" "8.52.0" 1352 + "@typescript-eslint/visitor-keys" "8.52.0" 1353 + ignore "^7.0.5" 1354 + natural-compare "^1.4.0" 1355 + ts-api-utils "^2.4.0" 1375 1356 1376 - "@typescript-eslint/experimental-utils@^5.0.0": 1377 - version "5.62.0" 1378 - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz#14559bf73383a308026b427a4a6129bae2146741" 1379 - integrity sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw== 1357 + "@typescript-eslint/parser@8.52.0": 1358 + version "8.52.0" 1359 + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.52.0.tgz#9fae9f5f13ebb1c8f31a50c34381bfd6bf96a05f" 1360 + integrity sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg== 1380 1361 dependencies: 1381 - "@typescript-eslint/utils" "5.62.0" 1362 + "@typescript-eslint/scope-manager" "8.52.0" 1363 + "@typescript-eslint/types" "8.52.0" 1364 + "@typescript-eslint/typescript-estree" "8.52.0" 1365 + "@typescript-eslint/visitor-keys" "8.52.0" 1366 + debug "^4.4.3" 1382 1367 1383 - "@typescript-eslint/scope-manager@5.62.0": 1384 - version "5.62.0" 1385 - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" 1386 - integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== 1368 + "@typescript-eslint/project-service@8.52.0": 1369 + version "8.52.0" 1370 + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.52.0.tgz#5fb4c16af4eda6d74c70cbc62f5d3f77b96e4cbe" 1371 + integrity sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw== 1387 1372 dependencies: 1388 - "@typescript-eslint/types" "5.62.0" 1389 - "@typescript-eslint/visitor-keys" "5.62.0" 1373 + "@typescript-eslint/tsconfig-utils" "^8.52.0" 1374 + "@typescript-eslint/types" "^8.52.0" 1375 + debug "^4.4.3" 1390 1376 1391 - "@typescript-eslint/types@5.62.0": 1392 - version "5.62.0" 1393 - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" 1394 - integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== 1377 + "@typescript-eslint/scope-manager@8.52.0": 1378 + version "8.52.0" 1379 + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.52.0.tgz#9884ff690fad30380ccabfb08af1ac200af6b4e5" 1380 + integrity sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA== 1381 + dependencies: 1382 + "@typescript-eslint/types" "8.52.0" 1383 + "@typescript-eslint/visitor-keys" "8.52.0" 1395 1384 1396 - "@typescript-eslint/typescript-estree@5.62.0": 1397 - version "5.62.0" 1398 - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" 1399 - integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== 1385 + "@typescript-eslint/tsconfig-utils@8.52.0", "@typescript-eslint/tsconfig-utils@^8.52.0": 1386 + version "8.52.0" 1387 + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.52.0.tgz#0296751c22ed05c83787a6eaec65ae221bd8b8ed" 1388 + integrity sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg== 1389 + 1390 + "@typescript-eslint/type-utils@8.52.0": 1391 + version "8.52.0" 1392 + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.52.0.tgz#6e554113f8a074cf9b2faa818d2ebfccb867d6c5" 1393 + integrity sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ== 1400 1394 dependencies: 1401 - "@typescript-eslint/types" "5.62.0" 1402 - "@typescript-eslint/visitor-keys" "5.62.0" 1403 - debug "^4.3.4" 1404 - globby "^11.1.0" 1405 - is-glob "^4.0.3" 1406 - semver "^7.3.7" 1407 - tsutils "^3.21.0" 1395 + "@typescript-eslint/types" "8.52.0" 1396 + "@typescript-eslint/typescript-estree" "8.52.0" 1397 + "@typescript-eslint/utils" "8.52.0" 1398 + debug "^4.4.3" 1399 + ts-api-utils "^2.4.0" 1408 1400 1409 - "@typescript-eslint/utils@5.62.0": 1410 - version "5.62.0" 1411 - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" 1412 - integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== 1401 + "@typescript-eslint/types@8.52.0", "@typescript-eslint/types@^8.52.0": 1402 + version "8.52.0" 1403 + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.52.0.tgz#1eb0a16b324824bc23b89d109a267c38c9213c4a" 1404 + integrity sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg== 1405 + 1406 + "@typescript-eslint/typescript-estree@8.52.0": 1407 + version "8.52.0" 1408 + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.52.0.tgz#2ad7721c671be2127951286cb7f44c4ce55b0591" 1409 + integrity sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ== 1413 1410 dependencies: 1414 - "@eslint-community/eslint-utils" "^4.2.0" 1415 - "@types/json-schema" "^7.0.9" 1416 - "@types/semver" "^7.3.12" 1417 - "@typescript-eslint/scope-manager" "5.62.0" 1418 - "@typescript-eslint/types" "5.62.0" 1419 - "@typescript-eslint/typescript-estree" "5.62.0" 1420 - eslint-scope "^5.1.1" 1421 - semver "^7.3.7" 1411 + "@typescript-eslint/project-service" "8.52.0" 1412 + "@typescript-eslint/tsconfig-utils" "8.52.0" 1413 + "@typescript-eslint/types" "8.52.0" 1414 + "@typescript-eslint/visitor-keys" "8.52.0" 1415 + debug "^4.4.3" 1416 + minimatch "^9.0.5" 1417 + semver "^7.7.3" 1418 + tinyglobby "^0.2.15" 1419 + ts-api-utils "^2.4.0" 1422 1420 1423 - "@typescript-eslint/visitor-keys@5.62.0": 1424 - version "5.62.0" 1425 - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" 1426 - integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== 1421 + "@typescript-eslint/utils@8.52.0": 1422 + version "8.52.0" 1423 + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.52.0.tgz#b249be8264899b80d996fa353b4b84da4662f962" 1424 + integrity sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ== 1427 1425 dependencies: 1428 - "@typescript-eslint/types" "5.62.0" 1429 - eslint-visitor-keys "^3.3.0" 1426 + "@eslint-community/eslint-utils" "^4.9.1" 1427 + "@typescript-eslint/scope-manager" "8.52.0" 1428 + "@typescript-eslint/types" "8.52.0" 1429 + "@typescript-eslint/typescript-estree" "8.52.0" 1430 1430 1431 - "@ungap/structured-clone@^1.2.0": 1432 - version "1.2.0" 1433 - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" 1434 - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== 1431 + "@typescript-eslint/visitor-keys@8.52.0": 1432 + version "8.52.0" 1433 + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.52.0.tgz#50361c48a6302676230fe498f80f6decce4bf673" 1434 + integrity sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ== 1435 + dependencies: 1436 + "@typescript-eslint/types" "8.52.0" 1437 + eslint-visitor-keys "^4.2.1" 1435 1438 1436 1439 "@vitejs/plugin-legacy@^7.0.0": 1437 1440 version "7.0.0" ··· 1457 1460 resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" 1458 1461 integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== 1459 1462 1460 - acorn@^8.14.0: 1463 + acorn@^8.14.0, acorn@^8.15.0: 1461 1464 version "8.15.0" 1462 1465 resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" 1463 1466 integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== 1464 - 1465 - acorn@^8.9.0: 1466 - version "8.11.3" 1467 - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" 1468 - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== 1469 1467 1470 1468 ajv@8.12.0: 1471 1469 version "8.12.0" ··· 1544 1542 resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 1545 1543 integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 1546 1544 1547 - array-buffer-byte-length@^1.0.1: 1548 - version "1.0.1" 1549 - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" 1550 - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== 1551 - dependencies: 1552 - call-bind "^1.0.5" 1553 - is-array-buffer "^3.0.4" 1554 - 1555 - array-includes@^3.1.6, array-includes@^3.1.7: 1556 - version "3.1.8" 1557 - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" 1558 - integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== 1559 - dependencies: 1560 - call-bind "^1.0.7" 1561 - define-properties "^1.2.1" 1562 - es-abstract "^1.23.2" 1563 - es-object-atoms "^1.0.0" 1564 - get-intrinsic "^1.2.4" 1565 - is-string "^1.0.7" 1566 - 1567 - array-union@^2.1.0: 1568 - version "2.1.0" 1569 - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" 1570 - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== 1571 - 1572 - array.prototype.findlast@^1.2.4: 1573 - version "1.2.5" 1574 - resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" 1575 - integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== 1576 - dependencies: 1577 - call-bind "^1.0.7" 1578 - define-properties "^1.2.1" 1579 - es-abstract "^1.23.2" 1580 - es-errors "^1.3.0" 1581 - es-object-atoms "^1.0.0" 1582 - es-shim-unscopables "^1.0.2" 1583 - 1584 - array.prototype.flat@^1.3.1: 1585 - version "1.3.2" 1586 - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" 1587 - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== 1588 - dependencies: 1589 - call-bind "^1.0.2" 1590 - define-properties "^1.2.0" 1591 - es-abstract "^1.22.1" 1592 - es-shim-unscopables "^1.0.0" 1593 - 1594 - array.prototype.flatmap@^1.3.2: 1595 - version "1.3.2" 1596 - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" 1597 - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== 1598 - dependencies: 1599 - call-bind "^1.0.2" 1600 - define-properties "^1.2.0" 1601 - es-abstract "^1.22.1" 1602 - es-shim-unscopables "^1.0.0" 1603 - 1604 - array.prototype.toreversed@^1.1.2: 1605 - version "1.1.2" 1606 - resolved "https://registry.yarnpkg.com/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz#b989a6bf35c4c5051e1dc0325151bf8088954eba" 1607 - integrity sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA== 1608 - dependencies: 1609 - call-bind "^1.0.2" 1610 - define-properties "^1.2.0" 1611 - es-abstract "^1.22.1" 1612 - es-shim-unscopables "^1.0.0" 1613 - 1614 - array.prototype.tosorted@^1.1.3: 1615 - version "1.1.3" 1616 - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz#c8c89348337e51b8a3c48a9227f9ce93ceedcba8" 1617 - integrity sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg== 1618 - dependencies: 1619 - call-bind "^1.0.5" 1620 - define-properties "^1.2.1" 1621 - es-abstract "^1.22.3" 1622 - es-errors "^1.1.0" 1623 - es-shim-unscopables "^1.0.2" 1624 - 1625 - arraybuffer.prototype.slice@^1.0.3: 1626 - version "1.0.3" 1627 - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" 1628 - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== 1629 - dependencies: 1630 - array-buffer-byte-length "^1.0.1" 1631 - call-bind "^1.0.5" 1632 - define-properties "^1.2.1" 1633 - es-abstract "^1.22.3" 1634 - es-errors "^1.2.1" 1635 - get-intrinsic "^1.2.3" 1636 - is-array-buffer "^3.0.4" 1637 - is-shared-array-buffer "^1.0.2" 1638 - 1639 - ast-metadata-inferer@^0.8.0: 1640 - version "0.8.0" 1641 - resolved "https://registry.yarnpkg.com/ast-metadata-inferer/-/ast-metadata-inferer-0.8.0.tgz#0f94c3425e310d8da45823ab2161142e3f134343" 1642 - integrity sha512-jOMKcHht9LxYIEQu+RVd22vtgrPaVCtDRQ/16IGmurdzxvYbDd5ynxjnyrzLnieG96eTcAyaoj/wN/4/1FyyeA== 1643 - dependencies: 1644 - "@mdn/browser-compat-data" "^5.2.34" 1645 - 1646 1545 autoprefixer@^10.4.19: 1647 1546 version "10.4.21" 1648 1547 resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.21.tgz#77189468e7a8ad1d9a37fbc08efc9f480cf0a95d" ··· 1654 1553 normalize-range "^0.1.2" 1655 1554 picocolors "^1.1.1" 1656 1555 postcss-value-parser "^4.2.0" 1657 - 1658 - available-typed-arrays@^1.0.7: 1659 - version "1.0.7" 1660 - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" 1661 - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== 1662 - dependencies: 1663 - possible-typed-array-names "^1.0.0" 1664 1556 1665 1557 await-lock@^2.2.2: 1666 1558 version "2.2.2" ··· 1754 1646 dependencies: 1755 1647 meow "^13.0.0" 1756 1648 1757 - browserslist@^4.21.10: 1758 - version "4.23.0" 1759 - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" 1760 - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== 1761 - dependencies: 1762 - caniuse-lite "^1.0.30001587" 1763 - electron-to-chromium "^1.4.668" 1764 - node-releases "^2.0.14" 1765 - update-browserslist-db "^1.0.13" 1766 - 1767 1649 browserslist@^4.24.0, browserslist@^4.24.4, browserslist@^4.25.0, browserslist@^4.25.1: 1768 1650 version "4.25.1" 1769 1651 resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" ··· 1789 1671 resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" 1790 1672 integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== 1791 1673 1792 - call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: 1793 - version "1.0.7" 1794 - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" 1795 - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== 1796 - dependencies: 1797 - es-define-property "^1.0.0" 1798 - es-errors "^1.3.0" 1799 - function-bind "^1.1.2" 1800 - get-intrinsic "^1.2.4" 1801 - set-function-length "^1.2.1" 1802 - 1803 1674 callsites@^3.0.0: 1804 1675 version "3.1.0" 1805 1676 resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" ··· 1815 1686 resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" 1816 1687 integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== 1817 1688 1818 - caniuse-lite@^1.0.30001524: 1819 - version "1.0.30001606" 1820 - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz#b4d5f67ab0746a3b8b5b6d1f06e39c51beb39a9e" 1821 - integrity sha512-LPbwnW4vfpJId225pwjZJOgX1m9sGfbw/RKJvw/t0QhYOOaTXHvkjVGFGPpvwEzufrjvTlsULnVTxdy4/6cqkg== 1822 - 1823 - caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001726: 1689 + caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001726: 1824 1690 version "1.0.30001727" 1825 1691 resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz#22e9706422ad37aa50556af8c10e40e2d93a8b85" 1826 1692 integrity sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q== ··· 1948 1814 resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.44.0.tgz#db4fd4fa07933c1d6898c8b112a1119a9336e959" 1949 1815 integrity sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw== 1950 1816 1951 - cross-spawn@^7.0.0, cross-spawn@^7.0.2: 1817 + cross-spawn@^7.0.0: 1952 1818 version "7.0.3" 1953 1819 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 1954 1820 integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== ··· 1957 1823 shebang-command "^2.0.0" 1958 1824 which "^2.0.1" 1959 1825 1960 - cross-spawn@^7.0.3: 1826 + cross-spawn@^7.0.3, cross-spawn@^7.0.6: 1961 1827 version "7.0.6" 1962 1828 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" 1963 1829 integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== ··· 1987 1853 resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" 1988 1854 integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== 1989 1855 1990 - data-view-buffer@^1.0.1: 1991 - version "1.0.1" 1992 - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" 1993 - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== 1994 - dependencies: 1995 - call-bind "^1.0.6" 1996 - es-errors "^1.3.0" 1997 - is-data-view "^1.0.1" 1998 - 1999 - data-view-byte-length@^1.0.1: 2000 - version "1.0.1" 2001 - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" 2002 - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== 2003 - dependencies: 2004 - call-bind "^1.0.7" 2005 - es-errors "^1.3.0" 2006 - is-data-view "^1.0.1" 2007 - 2008 - data-view-byte-offset@^1.0.0: 2009 - version "1.0.0" 2010 - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" 2011 - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== 2012 - dependencies: 2013 - call-bind "^1.0.6" 2014 - es-errors "^1.3.0" 2015 - is-data-view "^1.0.1" 2016 - 2017 1856 debug@2.6.9: 2018 1857 version "2.6.9" 2019 1858 resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" ··· 2035 1874 dependencies: 2036 1875 ms "2.1.2" 2037 1876 1877 + debug@^4.4.3: 1878 + version "4.4.3" 1879 + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" 1880 + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== 1881 + dependencies: 1882 + ms "^2.1.3" 1883 + 2038 1884 deep-extend@^0.6.0: 2039 1885 version "0.6.0" 2040 1886 resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" ··· 2045 1891 resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" 2046 1892 integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 2047 1893 2048 - define-data-property@^1.0.1, define-data-property@^1.1.4: 2049 - version "1.1.4" 2050 - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" 2051 - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== 2052 - dependencies: 2053 - es-define-property "^1.0.0" 2054 - es-errors "^1.3.0" 2055 - gopd "^1.0.1" 2056 - 2057 - define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: 2058 - version "1.2.1" 2059 - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" 2060 - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== 2061 - dependencies: 2062 - define-data-property "^1.0.1" 2063 - has-property-descriptors "^1.0.0" 2064 - object-keys "^1.1.1" 2065 - 2066 1894 didyoumean@^1.2.2: 2067 1895 version "1.2.2" 2068 1896 resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" 2069 1897 integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== 2070 1898 2071 - dir-glob@^3.0.1: 2072 - version "3.0.1" 2073 - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" 2074 - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== 2075 - dependencies: 2076 - path-type "^4.0.0" 2077 - 2078 1899 dlv@^1.1.3: 2079 1900 version "1.1.3" 2080 1901 resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" 2081 1902 integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== 2082 1903 2083 - doctrine@^2.1.0: 2084 - version "2.1.0" 2085 - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" 2086 - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== 2087 - dependencies: 2088 - esutils "^2.0.2" 2089 - 2090 - doctrine@^3.0.0: 2091 - version "3.0.0" 2092 - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 2093 - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 2094 - dependencies: 2095 - esutils "^2.0.2" 2096 - 2097 1904 dom-serializer@^2.0.0: 2098 1905 version "2.0.0" 2099 1906 resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" ··· 2129 1936 resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" 2130 1937 integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== 2131 1938 2132 - electron-to-chromium@^1.4.668, electron-to-chromium@^1.5.173: 1939 + electron-to-chromium@^1.5.173: 2133 1940 version "1.5.182" 2134 1941 resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz#4ab73104f893938acb3ab9c28d7bec170c116b3e" 2135 1942 integrity sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA== ··· 2149 1956 resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" 2150 1957 integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== 2151 1958 2152 - es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2: 2153 - version "1.23.3" 2154 - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" 2155 - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== 2156 - dependencies: 2157 - array-buffer-byte-length "^1.0.1" 2158 - arraybuffer.prototype.slice "^1.0.3" 2159 - available-typed-arrays "^1.0.7" 2160 - call-bind "^1.0.7" 2161 - data-view-buffer "^1.0.1" 2162 - data-view-byte-length "^1.0.1" 2163 - data-view-byte-offset "^1.0.0" 2164 - es-define-property "^1.0.0" 2165 - es-errors "^1.3.0" 2166 - es-object-atoms "^1.0.0" 2167 - es-set-tostringtag "^2.0.3" 2168 - es-to-primitive "^1.2.1" 2169 - function.prototype.name "^1.1.6" 2170 - get-intrinsic "^1.2.4" 2171 - get-symbol-description "^1.0.2" 2172 - globalthis "^1.0.3" 2173 - gopd "^1.0.1" 2174 - has-property-descriptors "^1.0.2" 2175 - has-proto "^1.0.3" 2176 - has-symbols "^1.0.3" 2177 - hasown "^2.0.2" 2178 - internal-slot "^1.0.7" 2179 - is-array-buffer "^3.0.4" 2180 - is-callable "^1.2.7" 2181 - is-data-view "^1.0.1" 2182 - is-negative-zero "^2.0.3" 2183 - is-regex "^1.1.4" 2184 - is-shared-array-buffer "^1.0.3" 2185 - is-string "^1.0.7" 2186 - is-typed-array "^1.1.13" 2187 - is-weakref "^1.0.2" 2188 - object-inspect "^1.13.1" 2189 - object-keys "^1.1.1" 2190 - object.assign "^4.1.5" 2191 - regexp.prototype.flags "^1.5.2" 2192 - safe-array-concat "^1.1.2" 2193 - safe-regex-test "^1.0.3" 2194 - string.prototype.trim "^1.2.9" 2195 - string.prototype.trimend "^1.0.8" 2196 - string.prototype.trimstart "^1.0.8" 2197 - typed-array-buffer "^1.0.2" 2198 - typed-array-byte-length "^1.0.1" 2199 - typed-array-byte-offset "^1.0.2" 2200 - typed-array-length "^1.0.6" 2201 - unbox-primitive "^1.0.2" 2202 - which-typed-array "^1.1.15" 2203 - 2204 - es-define-property@^1.0.0: 2205 - version "1.0.0" 2206 - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" 2207 - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== 2208 - dependencies: 2209 - get-intrinsic "^1.2.4" 2210 - 2211 - es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: 2212 - version "1.3.0" 2213 - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" 2214 - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== 2215 - 2216 - es-iterator-helpers@^1.0.17: 2217 - version "1.0.18" 2218 - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz#4d3424f46b24df38d064af6fbbc89274e29ea69d" 2219 - integrity sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA== 2220 - dependencies: 2221 - call-bind "^1.0.7" 2222 - define-properties "^1.2.1" 2223 - es-abstract "^1.23.0" 2224 - es-errors "^1.3.0" 2225 - es-set-tostringtag "^2.0.3" 2226 - function-bind "^1.1.2" 2227 - get-intrinsic "^1.2.4" 2228 - globalthis "^1.0.3" 2229 - has-property-descriptors "^1.0.2" 2230 - has-proto "^1.0.3" 2231 - has-symbols "^1.0.3" 2232 - internal-slot "^1.0.7" 2233 - iterator.prototype "^1.1.2" 2234 - safe-array-concat "^1.1.2" 2235 - 2236 - es-object-atoms@^1.0.0: 2237 - version "1.0.0" 2238 - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" 2239 - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== 2240 - dependencies: 2241 - es-errors "^1.3.0" 2242 - 2243 - es-set-tostringtag@^2.0.3: 2244 - version "2.0.3" 2245 - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" 2246 - integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== 2247 - dependencies: 2248 - get-intrinsic "^1.2.4" 2249 - has-tostringtag "^1.0.2" 2250 - hasown "^2.0.1" 2251 - 2252 - es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: 2253 - version "1.0.2" 2254 - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" 2255 - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== 2256 - dependencies: 2257 - hasown "^2.0.0" 2258 - 2259 - es-to-primitive@^1.2.1: 2260 - version "1.2.1" 2261 - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" 2262 - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== 2263 - dependencies: 2264 - is-callable "^1.1.4" 2265 - is-date-object "^1.0.1" 2266 - is-symbol "^1.0.2" 2267 - 2268 1959 esbuild@^0.25.0: 2269 1960 version "0.25.6" 2270 1961 resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.6.tgz#9b82a3db2fa131aec069ab040fd57ed0a880cdcd" ··· 2307 1998 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 2308 1999 integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 2309 2000 2310 - eslint-config-preact@^1.3.0: 2311 - version "1.3.0" 2312 - resolved "https://registry.yarnpkg.com/eslint-config-preact/-/eslint-config-preact-1.3.0.tgz#17b72813078f4d1d4d2b79938ec21f92338bc9c0" 2313 - integrity sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw== 2314 - dependencies: 2315 - "@babel/core" "^7.13.16" 2316 - "@babel/eslint-parser" "^7.13.14" 2317 - "@babel/plugin-syntax-class-properties" "^7.12.13" 2318 - "@babel/plugin-syntax-decorators" "^7.12.13" 2319 - "@babel/plugin-syntax-jsx" "^7.12.13" 2320 - eslint-plugin-compat "^4.0.0" 2321 - eslint-plugin-jest "^25.2.4" 2322 - eslint-plugin-react "^7.27.0" 2323 - eslint-plugin-react-hooks "^4.3.0" 2324 - 2325 - eslint-plugin-compat@^4.0.0: 2326 - version "4.2.0" 2327 - resolved "https://registry.yarnpkg.com/eslint-plugin-compat/-/eslint-plugin-compat-4.2.0.tgz#eeaf80daa1afe495c88a47e9281295acae45c0aa" 2328 - integrity sha512-RDKSYD0maWy5r7zb5cWQS+uSPc26mgOzdORJ8hxILmWM7S/Ncwky7BcAtXVY5iRbKjBdHsWU8Yg7hfoZjtkv7w== 2329 - dependencies: 2330 - "@mdn/browser-compat-data" "^5.3.13" 2331 - ast-metadata-inferer "^0.8.0" 2332 - browserslist "^4.21.10" 2333 - caniuse-lite "^1.0.30001524" 2334 - find-up "^5.0.0" 2335 - lodash.memoize "^4.1.2" 2336 - semver "^7.5.4" 2337 - 2338 - eslint-plugin-jest@^25.2.4: 2339 - version "25.7.0" 2340 - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz#ff4ac97520b53a96187bad9c9814e7d00de09a6a" 2341 - integrity sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ== 2342 - dependencies: 2343 - "@typescript-eslint/experimental-utils" "^5.0.0" 2344 - 2345 - eslint-plugin-react-hooks@^4.3.0: 2346 - version "4.6.0" 2347 - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" 2348 - integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== 2349 - 2350 - eslint-plugin-react@^7.27.0: 2351 - version "7.34.1" 2352 - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz#6806b70c97796f5bbfb235a5d3379ece5f4da997" 2353 - integrity sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw== 2354 - dependencies: 2355 - array-includes "^3.1.7" 2356 - array.prototype.findlast "^1.2.4" 2357 - array.prototype.flatmap "^1.3.2" 2358 - array.prototype.toreversed "^1.1.2" 2359 - array.prototype.tosorted "^1.1.3" 2360 - doctrine "^2.1.0" 2361 - es-iterator-helpers "^1.0.17" 2362 - estraverse "^5.3.0" 2363 - jsx-ast-utils "^2.4.1 || ^3.0.0" 2364 - minimatch "^3.1.2" 2365 - object.entries "^1.1.7" 2366 - object.fromentries "^2.0.7" 2367 - object.hasown "^1.1.3" 2368 - object.values "^1.1.7" 2369 - prop-types "^15.8.1" 2370 - resolve "^2.0.0-next.5" 2371 - semver "^6.3.1" 2372 - string.prototype.matchall "^4.0.10" 2373 - 2374 - eslint-plugin-simple-import-sort@^12.0.0: 2375 - version "12.0.0" 2376 - resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.0.0.tgz#3cfa05d74509bd4dc329a956938823812194dbb6" 2377 - integrity sha512-8o0dVEdAkYap0Cn5kNeklaKcT1nUsa3LITWEuFk3nJifOoD+5JQGoyDUW2W/iPWwBsNBJpyJS9y4je/BgxLcyQ== 2378 - 2379 - eslint-scope@5.1.1, eslint-scope@^5.1.1: 2380 - version "5.1.1" 2381 - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" 2382 - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== 2383 - dependencies: 2384 - esrecurse "^4.3.0" 2385 - estraverse "^4.1.1" 2001 + eslint-plugin-simple-import-sort@^12.1.1: 2002 + version "12.1.1" 2003 + resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz#e64bfdaf91c5b98a298619aa634a9f7aa43b709e" 2004 + integrity sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA== 2386 2005 2387 - eslint-scope@^7.2.2: 2388 - version "7.2.2" 2389 - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" 2390 - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== 2006 + eslint-scope@^8.4.0: 2007 + version "8.4.0" 2008 + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" 2009 + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== 2391 2010 dependencies: 2392 2011 esrecurse "^4.3.0" 2393 2012 estraverse "^5.2.0" 2394 2013 2395 - eslint-visitor-keys@^2.1.0: 2396 - version "2.1.0" 2397 - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" 2398 - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== 2399 - 2400 - eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: 2014 + eslint-visitor-keys@^3.4.3: 2401 2015 version "3.4.3" 2402 2016 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" 2403 2017 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== 2404 2018 2405 - eslint@^8.19.0: 2406 - version "8.57.0" 2407 - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" 2408 - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== 2019 + eslint-visitor-keys@^4.2.1: 2020 + version "4.2.1" 2021 + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" 2022 + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== 2023 + 2024 + eslint@^9.18.0: 2025 + version "9.39.2" 2026 + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.2.tgz#cb60e6d16ab234c0f8369a3fe7cc87967faf4b6c" 2027 + integrity sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw== 2409 2028 dependencies: 2410 - "@eslint-community/eslint-utils" "^4.2.0" 2411 - "@eslint-community/regexpp" "^4.6.1" 2412 - "@eslint/eslintrc" "^2.1.4" 2413 - "@eslint/js" "8.57.0" 2414 - "@humanwhocodes/config-array" "^0.11.14" 2029 + "@eslint-community/eslint-utils" "^4.8.0" 2030 + "@eslint-community/regexpp" "^4.12.1" 2031 + "@eslint/config-array" "^0.21.1" 2032 + "@eslint/config-helpers" "^0.4.2" 2033 + "@eslint/core" "^0.17.0" 2034 + "@eslint/eslintrc" "^3.3.1" 2035 + "@eslint/js" "9.39.2" 2036 + "@eslint/plugin-kit" "^0.4.1" 2037 + "@humanfs/node" "^0.16.6" 2415 2038 "@humanwhocodes/module-importer" "^1.0.1" 2416 - "@nodelib/fs.walk" "^1.2.8" 2417 - "@ungap/structured-clone" "^1.2.0" 2039 + "@humanwhocodes/retry" "^0.4.2" 2040 + "@types/estree" "^1.0.6" 2418 2041 ajv "^6.12.4" 2419 2042 chalk "^4.0.0" 2420 - cross-spawn "^7.0.2" 2043 + cross-spawn "^7.0.6" 2421 2044 debug "^4.3.2" 2422 - doctrine "^3.0.0" 2423 2045 escape-string-regexp "^4.0.0" 2424 - eslint-scope "^7.2.2" 2425 - eslint-visitor-keys "^3.4.3" 2426 - espree "^9.6.1" 2427 - esquery "^1.4.2" 2046 + eslint-scope "^8.4.0" 2047 + eslint-visitor-keys "^4.2.1" 2048 + espree "^10.4.0" 2049 + esquery "^1.5.0" 2428 2050 esutils "^2.0.2" 2429 2051 fast-deep-equal "^3.1.3" 2430 - file-entry-cache "^6.0.1" 2052 + file-entry-cache "^8.0.0" 2431 2053 find-up "^5.0.0" 2432 2054 glob-parent "^6.0.2" 2433 - globals "^13.19.0" 2434 - graphemer "^1.4.0" 2435 2055 ignore "^5.2.0" 2436 2056 imurmurhash "^0.1.4" 2437 2057 is-glob "^4.0.0" 2438 - is-path-inside "^3.0.3" 2439 - js-yaml "^4.1.0" 2440 2058 json-stable-stringify-without-jsonify "^1.0.1" 2441 - levn "^0.4.1" 2442 2059 lodash.merge "^4.6.2" 2443 2060 minimatch "^3.1.2" 2444 2061 natural-compare "^1.4.0" 2445 2062 optionator "^0.9.3" 2446 - strip-ansi "^6.0.1" 2447 - text-table "^0.2.0" 2448 2063 2449 - espree@^9.6.0, espree@^9.6.1: 2450 - version "9.6.1" 2451 - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" 2452 - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== 2064 + espree@^10.0.1, espree@^10.4.0: 2065 + version "10.4.0" 2066 + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" 2067 + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== 2453 2068 dependencies: 2454 - acorn "^8.9.0" 2069 + acorn "^8.15.0" 2455 2070 acorn-jsx "^5.3.2" 2456 - eslint-visitor-keys "^3.4.1" 2071 + eslint-visitor-keys "^4.2.1" 2457 2072 2458 - esquery@^1.4.2: 2459 - version "1.5.0" 2460 - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" 2461 - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== 2073 + esquery@^1.5.0: 2074 + version "1.7.0" 2075 + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" 2076 + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== 2462 2077 dependencies: 2463 2078 estraverse "^5.1.0" 2464 2079 ··· 2469 2084 dependencies: 2470 2085 estraverse "^5.2.0" 2471 2086 2472 - estraverse@^4.1.1: 2473 - version "4.3.0" 2474 - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" 2475 - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== 2476 - 2477 - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: 2087 + estraverse@^5.1.0, estraverse@^5.2.0: 2478 2088 version "5.3.0" 2479 2089 resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" 2480 2090 integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== ··· 2509 2119 resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 2510 2120 integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 2511 2121 2512 - fast-glob@^3.2.9, fast-glob@^3.3.0: 2122 + fast-glob@^3.3.0: 2513 2123 version "3.3.2" 2514 2124 resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" 2515 2125 integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== ··· 2542 2152 resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281" 2543 2153 integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w== 2544 2154 2545 - file-entry-cache@^6.0.1: 2546 - version "6.0.1" 2547 - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 2548 - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 2155 + fdir@^6.5.0: 2156 + version "6.5.0" 2157 + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" 2158 + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== 2159 + 2160 + file-entry-cache@^8.0.0: 2161 + version "8.0.0" 2162 + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" 2163 + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== 2549 2164 dependencies: 2550 - flat-cache "^3.0.4" 2165 + flat-cache "^4.0.0" 2551 2166 2552 2167 fill-range@^7.0.1: 2553 2168 version "7.0.1" ··· 2564 2179 locate-path "^6.0.0" 2565 2180 path-exists "^4.0.0" 2566 2181 2567 - flat-cache@^3.0.4: 2568 - version "3.2.0" 2569 - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" 2570 - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== 2182 + flat-cache@^4.0.0: 2183 + version "4.0.1" 2184 + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" 2185 + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== 2571 2186 dependencies: 2572 2187 flatted "^3.2.9" 2573 - keyv "^4.5.3" 2574 - rimraf "^3.0.2" 2188 + keyv "^4.5.4" 2575 2189 2576 2190 flatted@^3.2.9: 2577 2191 version "3.3.1" 2578 2192 resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" 2579 2193 integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== 2580 2194 2581 - for-each@^0.3.3: 2582 - version "0.3.3" 2583 - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" 2584 - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== 2585 - dependencies: 2586 - is-callable "^1.1.3" 2587 - 2588 2195 foreground-child@^3.1.0: 2589 2196 version "3.1.1" 2590 2197 resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" ··· 2598 2205 resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" 2599 2206 integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== 2600 2207 2601 - fs.realpath@^1.0.0: 2602 - version "1.0.0" 2603 - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 2604 - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 2605 - 2606 2208 fsevents@~2.3.2, fsevents@~2.3.3: 2607 2209 version "2.3.3" 2608 2210 resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" ··· 2613 2215 resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 2614 2216 integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 2615 2217 2616 - function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: 2617 - version "1.1.6" 2618 - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" 2619 - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== 2620 - dependencies: 2621 - call-bind "^1.0.2" 2622 - define-properties "^1.2.0" 2623 - es-abstract "^1.22.1" 2624 - functions-have-names "^1.2.3" 2625 - 2626 - functions-have-names@^1.2.3: 2627 - version "1.2.3" 2628 - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" 2629 - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== 2630 - 2631 2218 gensync@^1.0.0-beta.2: 2632 2219 version "1.0.0-beta.2" 2633 2220 resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" 2634 2221 integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== 2635 2222 2636 - get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: 2637 - version "1.2.4" 2638 - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" 2639 - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== 2640 - dependencies: 2641 - es-errors "^1.3.0" 2642 - function-bind "^1.1.2" 2643 - has-proto "^1.0.1" 2644 - has-symbols "^1.0.3" 2645 - hasown "^2.0.0" 2646 - 2647 2223 get-stream@^6.0.0: 2648 2224 version "6.0.1" 2649 2225 resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" 2650 2226 integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== 2651 - 2652 - get-symbol-description@^1.0.2: 2653 - version "1.0.2" 2654 - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" 2655 - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== 2656 - dependencies: 2657 - call-bind "^1.0.5" 2658 - es-errors "^1.3.0" 2659 - get-intrinsic "^1.2.4" 2660 2227 2661 2228 glob-parent@^5.1.2, glob-parent@~5.1.2: 2662 2229 version "5.1.2" ··· 2683 2250 minipass "^7.0.4" 2684 2251 path-scurry "^1.10.2" 2685 2252 2686 - glob@^7.1.3: 2687 - version "7.2.3" 2688 - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 2689 - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 2690 - dependencies: 2691 - fs.realpath "^1.0.0" 2692 - inflight "^1.0.4" 2693 - inherits "2" 2694 - minimatch "^3.1.1" 2695 - once "^1.3.0" 2696 - path-is-absolute "^1.0.0" 2697 - 2698 - globals@^13.19.0: 2699 - version "13.24.0" 2700 - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" 2701 - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== 2702 - dependencies: 2703 - type-fest "^0.20.2" 2704 - 2705 - globalthis@^1.0.3: 2706 - version "1.0.3" 2707 - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" 2708 - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== 2709 - dependencies: 2710 - define-properties "^1.1.3" 2253 + globals@^14.0.0: 2254 + version "14.0.0" 2255 + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" 2256 + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== 2711 2257 2712 - globby@^11.1.0: 2713 - version "11.1.0" 2714 - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" 2715 - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== 2716 - dependencies: 2717 - array-union "^2.1.0" 2718 - dir-glob "^3.0.1" 2719 - fast-glob "^3.2.9" 2720 - ignore "^5.2.0" 2721 - merge2 "^1.4.1" 2722 - slash "^3.0.0" 2258 + globals@^15.14.0: 2259 + version "15.15.0" 2260 + resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" 2261 + integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== 2723 2262 2724 2263 globrex@^0.1.2: 2725 2264 version "0.1.2" 2726 2265 resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" 2727 2266 integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== 2728 - 2729 - gopd@^1.0.1: 2730 - version "1.0.1" 2731 - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" 2732 - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== 2733 - dependencies: 2734 - get-intrinsic "^1.1.3" 2735 2267 2736 2268 graphemer@^1.4.0: 2737 2269 version "1.4.0" 2738 2270 resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" 2739 2271 integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== 2740 2272 2741 - has-bigints@^1.0.1, has-bigints@^1.0.2: 2742 - version "1.0.2" 2743 - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" 2744 - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== 2745 - 2746 2273 has-flag@^4.0.0: 2747 2274 version "4.0.0" 2748 2275 resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 2749 2276 integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 2750 2277 2751 - has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: 2752 - version "1.0.2" 2753 - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" 2754 - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== 2755 - dependencies: 2756 - es-define-property "^1.0.0" 2757 - 2758 - has-proto@^1.0.1, has-proto@^1.0.3: 2759 - version "1.0.3" 2760 - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" 2761 - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== 2762 - 2763 - has-symbols@^1.0.2, has-symbols@^1.0.3: 2764 - version "1.0.3" 2765 - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" 2766 - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 2767 - 2768 - has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: 2769 - version "1.0.2" 2770 - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" 2771 - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== 2772 - dependencies: 2773 - has-symbols "^1.0.3" 2774 - 2775 - hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: 2278 + hasown@^2.0.0, hasown@^2.0.2: 2776 2279 version "2.0.2" 2777 2280 resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 2778 2281 integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== ··· 2794 2297 resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" 2795 2298 integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== 2796 2299 2300 + ignore@^7.0.5: 2301 + version "7.0.5" 2302 + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" 2303 + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== 2304 + 2797 2305 import-fresh@^3.2.1: 2798 2306 version "3.3.0" 2799 2307 resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" ··· 2807 2315 resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 2808 2316 integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 2809 2317 2810 - inflight@^1.0.4: 2811 - version "1.0.6" 2812 - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 2813 - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 2814 - dependencies: 2815 - once "^1.3.0" 2816 - wrappy "1" 2817 - 2818 - inherits@2: 2819 - version "2.0.4" 2820 - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 2821 - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 2822 - 2823 2318 ini@~1.3.0: 2824 2319 version "1.3.8" 2825 2320 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" 2826 2321 integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== 2827 2322 2828 - internal-slot@^1.0.7: 2829 - version "1.0.7" 2830 - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" 2831 - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== 2832 - dependencies: 2833 - es-errors "^1.3.0" 2834 - hasown "^2.0.0" 2835 - side-channel "^1.0.4" 2836 - 2837 - is-array-buffer@^3.0.4: 2838 - version "3.0.4" 2839 - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" 2840 - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== 2841 - dependencies: 2842 - call-bind "^1.0.2" 2843 - get-intrinsic "^1.2.1" 2844 - 2845 - is-async-function@^2.0.0: 2846 - version "2.0.0" 2847 - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" 2848 - integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== 2849 - dependencies: 2850 - has-tostringtag "^1.0.0" 2851 - 2852 - is-bigint@^1.0.1: 2853 - version "1.0.4" 2854 - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" 2855 - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== 2856 - dependencies: 2857 - has-bigints "^1.0.1" 2858 - 2859 2323 is-binary-path@~2.1.0: 2860 2324 version "2.1.0" 2861 2325 resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" ··· 2863 2327 dependencies: 2864 2328 binary-extensions "^2.0.0" 2865 2329 2866 - is-boolean-object@^1.1.0: 2867 - version "1.1.2" 2868 - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" 2869 - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== 2870 - dependencies: 2871 - call-bind "^1.0.2" 2872 - has-tostringtag "^1.0.0" 2873 - 2874 - is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: 2875 - version "1.2.7" 2876 - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" 2877 - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== 2878 - 2879 2330 is-core-module@^2.13.0: 2880 2331 version "2.13.1" 2881 2332 resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" ··· 2890 2341 dependencies: 2891 2342 hasown "^2.0.2" 2892 2343 2893 - is-data-view@^1.0.1: 2894 - version "1.0.1" 2895 - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" 2896 - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== 2897 - dependencies: 2898 - is-typed-array "^1.1.13" 2899 - 2900 - is-date-object@^1.0.1, is-date-object@^1.0.5: 2901 - version "1.0.5" 2902 - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" 2903 - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== 2904 - dependencies: 2905 - has-tostringtag "^1.0.0" 2906 - 2907 2344 is-docker@^2.0.0: 2908 2345 version "2.2.1" 2909 2346 resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" ··· 2914 2351 resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 2915 2352 integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 2916 2353 2917 - is-finalizationregistry@^1.0.2: 2918 - version "1.0.2" 2919 - resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" 2920 - integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== 2921 - dependencies: 2922 - call-bind "^1.0.2" 2923 - 2924 2354 is-fullwidth-code-point@^3.0.0: 2925 2355 version "3.0.0" 2926 2356 resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 2927 2357 integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 2928 2358 2929 - is-generator-function@^1.0.10: 2930 - version "1.0.10" 2931 - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" 2932 - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== 2933 - dependencies: 2934 - has-tostringtag "^1.0.0" 2935 - 2936 2359 is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: 2937 2360 version "4.0.3" 2938 2361 resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" ··· 2940 2363 dependencies: 2941 2364 is-extglob "^2.1.1" 2942 2365 2943 - is-map@^2.0.3: 2944 - version "2.0.3" 2945 - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" 2946 - integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== 2947 - 2948 - is-negative-zero@^2.0.3: 2949 - version "2.0.3" 2950 - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" 2951 - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== 2952 - 2953 - is-number-object@^1.0.4: 2954 - version "1.0.7" 2955 - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" 2956 - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== 2957 - dependencies: 2958 - has-tostringtag "^1.0.0" 2959 - 2960 2366 is-number@^7.0.0: 2961 2367 version "7.0.0" 2962 2368 resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 2963 2369 integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 2964 2370 2965 - is-path-inside@^3.0.3: 2966 - version "3.0.3" 2967 - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 2968 - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 2969 - 2970 2371 is-port-reachable@4.0.0: 2971 2372 version "4.0.0" 2972 2373 resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" 2973 2374 integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== 2974 2375 2975 - is-regex@^1.1.4: 2976 - version "1.1.4" 2977 - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" 2978 - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== 2979 - dependencies: 2980 - call-bind "^1.0.2" 2981 - has-tostringtag "^1.0.0" 2982 - 2983 - is-set@^2.0.3: 2984 - version "2.0.3" 2985 - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" 2986 - integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== 2987 - 2988 - is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: 2989 - version "1.0.3" 2990 - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" 2991 - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== 2992 - dependencies: 2993 - call-bind "^1.0.7" 2994 - 2995 2376 is-stream@^2.0.0: 2996 2377 version "2.0.1" 2997 2378 resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" 2998 2379 integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== 2999 2380 3000 - is-string@^1.0.5, is-string@^1.0.7: 3001 - version "1.0.7" 3002 - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" 3003 - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== 3004 - dependencies: 3005 - has-tostringtag "^1.0.0" 3006 - 3007 - is-symbol@^1.0.2, is-symbol@^1.0.3: 3008 - version "1.0.4" 3009 - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" 3010 - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== 3011 - dependencies: 3012 - has-symbols "^1.0.2" 3013 - 3014 - is-typed-array@^1.1.13: 3015 - version "1.1.13" 3016 - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" 3017 - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== 3018 - dependencies: 3019 - which-typed-array "^1.1.14" 3020 - 3021 - is-weakmap@^2.0.2: 3022 - version "2.0.2" 3023 - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" 3024 - integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== 3025 - 3026 - is-weakref@^1.0.2: 3027 - version "1.0.2" 3028 - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" 3029 - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== 3030 - dependencies: 3031 - call-bind "^1.0.2" 3032 - 3033 - is-weakset@^2.0.3: 3034 - version "2.0.3" 3035 - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" 3036 - integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== 3037 - dependencies: 3038 - call-bind "^1.0.7" 3039 - get-intrinsic "^1.2.4" 3040 - 3041 2381 is-wsl@^2.2.0: 3042 2382 version "2.2.0" 3043 2383 resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" ··· 3045 2385 dependencies: 3046 2386 is-docker "^2.0.0" 3047 2387 3048 - isarray@^2.0.5: 3049 - version "2.0.5" 3050 - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" 3051 - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== 3052 - 3053 2388 isexe@^2.0.0: 3054 2389 version "2.0.0" 3055 2390 resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" ··· 3060 2395 resolved "https://registry.yarnpkg.com/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz#2daa80d2900b7a954f9f731d42f96ee0c19a6895" 3061 2396 integrity sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA== 3062 2397 3063 - iterator.prototype@^1.1.2: 3064 - version "1.1.2" 3065 - resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" 3066 - integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== 3067 - dependencies: 3068 - define-properties "^1.2.1" 3069 - get-intrinsic "^1.2.1" 3070 - has-symbols "^1.0.3" 3071 - reflect.getprototypeof "^1.0.4" 3072 - set-function-name "^2.0.1" 3073 - 3074 2398 jackspeak@^2.3.6: 3075 2399 version "2.3.6" 3076 2400 resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" ··· 3085 2409 resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" 3086 2410 integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== 3087 2411 3088 - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: 2412 + js-tokens@^4.0.0: 3089 2413 version "4.0.0" 3090 2414 resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 3091 2415 integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 3092 2416 3093 - js-yaml@^4.1.0: 3094 - version "4.1.0" 3095 - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 3096 - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 2417 + js-yaml@^4.1.1: 2418 + version "4.1.1" 2419 + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" 2420 + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== 3097 2421 dependencies: 3098 2422 argparse "^2.0.1" 3099 2423 ··· 3132 2456 resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" 3133 2457 integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== 3134 2458 3135 - "jsx-ast-utils@^2.4.1 || ^3.0.0": 3136 - version "3.3.5" 3137 - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" 3138 - integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== 3139 - dependencies: 3140 - array-includes "^3.1.6" 3141 - array.prototype.flat "^1.3.1" 3142 - object.assign "^4.1.4" 3143 - object.values "^1.1.6" 3144 - 3145 - keyv@^4.5.3: 2459 + keyv@^4.5.4: 3146 2460 version "4.5.4" 3147 2461 resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" 3148 2462 integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== ··· 3189 2503 resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" 3190 2504 integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== 3191 2505 3192 - lodash.memoize@^4.1.2: 3193 - version "4.1.2" 3194 - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" 3195 - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== 3196 - 3197 2506 lodash.merge@^4.6.2: 3198 2507 version "4.6.2" 3199 2508 resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" 3200 2509 integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 3201 2510 3202 - loose-envify@^1.4.0: 3203 - version "1.4.0" 3204 - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 3205 - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 3206 - dependencies: 3207 - js-tokens "^3.0.0 || ^4.0.0" 3208 - 3209 2511 lru-cache@^10.2.0: 3210 2512 version "10.2.0" 3211 2513 resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" ··· 3218 2520 dependencies: 3219 2521 yallist "^3.0.2" 3220 2522 3221 - lru-cache@^6.0.0: 3222 - version "6.0.0" 3223 - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 3224 - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 3225 - dependencies: 3226 - yallist "^4.0.0" 3227 - 3228 2523 "magic-string@0.x >= 0.26.0", magic-string@^0.30.17: 3229 2524 version "0.30.17" 3230 2525 resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" ··· 3242 2537 resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" 3243 2538 integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== 3244 2539 3245 - merge2@^1.3.0, merge2@^1.4.1: 2540 + merge2@^1.3.0: 3246 2541 version "1.4.1" 3247 2542 resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 3248 2543 integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== ··· 3277 2572 resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 3278 2573 integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 3279 2574 3280 - minimatch@3.1.2, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: 2575 + minimatch@3.1.2, minimatch@^3.1.2: 3281 2576 version "3.1.2" 3282 2577 resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 3283 2578 integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== ··· 3291 2586 dependencies: 3292 2587 brace-expansion "^2.0.1" 3293 2588 2589 + minimatch@^9.0.5: 2590 + version "9.0.5" 2591 + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" 2592 + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== 2593 + dependencies: 2594 + brace-expansion "^2.0.1" 2595 + 3294 2596 minimist@^1.2.0: 3295 2597 version "1.2.8" 3296 2598 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" ··· 3358 2660 css-select "^5.1.0" 3359 2661 he "1.2.0" 3360 2662 3361 - node-releases@^2.0.14, node-releases@^2.0.19: 2663 + node-releases@^2.0.19: 3362 2664 version "2.0.19" 3363 2665 resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" 3364 2666 integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== ··· 3387 2689 dependencies: 3388 2690 boolbase "^1.0.0" 3389 2691 3390 - object-assign@^4.0.1, object-assign@^4.1.1: 2692 + object-assign@^4.0.1: 3391 2693 version "4.1.1" 3392 2694 resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 3393 2695 integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== ··· 3397 2699 resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" 3398 2700 integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== 3399 2701 3400 - object-inspect@^1.13.1: 3401 - version "1.13.1" 3402 - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" 3403 - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== 3404 - 3405 - object-keys@^1.1.1: 3406 - version "1.1.1" 3407 - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 3408 - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 3409 - 3410 - object.assign@^4.1.4, object.assign@^4.1.5: 3411 - version "4.1.5" 3412 - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" 3413 - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== 3414 - dependencies: 3415 - call-bind "^1.0.5" 3416 - define-properties "^1.2.1" 3417 - has-symbols "^1.0.3" 3418 - object-keys "^1.1.1" 3419 - 3420 - object.entries@^1.1.7: 3421 - version "1.1.8" 3422 - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" 3423 - integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== 3424 - dependencies: 3425 - call-bind "^1.0.7" 3426 - define-properties "^1.2.1" 3427 - es-object-atoms "^1.0.0" 3428 - 3429 - object.fromentries@^2.0.7: 3430 - version "2.0.8" 3431 - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" 3432 - integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== 3433 - dependencies: 3434 - call-bind "^1.0.7" 3435 - define-properties "^1.2.1" 3436 - es-abstract "^1.23.2" 3437 - es-object-atoms "^1.0.0" 3438 - 3439 - object.hasown@^1.1.3: 3440 - version "1.1.4" 3441 - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" 3442 - integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== 3443 - dependencies: 3444 - define-properties "^1.2.1" 3445 - es-abstract "^1.23.2" 3446 - es-object-atoms "^1.0.0" 3447 - 3448 - object.values@^1.1.6, object.values@^1.1.7: 3449 - version "1.2.0" 3450 - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" 3451 - integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== 3452 - dependencies: 3453 - call-bind "^1.0.7" 3454 - define-properties "^1.2.1" 3455 - es-object-atoms "^1.0.0" 3456 - 3457 2702 on-headers@~1.1.0: 3458 2703 version "1.1.0" 3459 2704 resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.1.0.tgz#59da4f91c45f5f989c6e4bcedc5a3b0aed70ff65" 3460 2705 integrity sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A== 3461 2706 3462 - once@^1.3.0: 3463 - version "1.4.0" 3464 - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 3465 - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 3466 - dependencies: 3467 - wrappy "1" 3468 - 3469 2707 onetime@^5.1.2: 3470 2708 version "5.1.2" 3471 2709 resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" ··· 3511 2749 resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 3512 2750 integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 3513 2751 3514 - path-is-absolute@^1.0.0: 3515 - version "1.0.1" 3516 - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 3517 - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 3518 - 3519 2752 path-is-inside@1.0.2: 3520 2753 version "1.0.2" 3521 2754 resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" ··· 3544 2777 resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.3.0.tgz#f7f31d32e8518c2660862b644414b6d5c63a611b" 3545 2778 integrity sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw== 3546 2779 3547 - path-type@^4.0.0: 3548 - version "4.0.0" 3549 - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 3550 - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 3551 - 3552 2780 picocolors@^1.0.0, picocolors@^1.1.1: 3553 2781 version "1.1.1" 3554 2782 resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" ··· 3564 2792 resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" 3565 2793 integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== 3566 2794 2795 + picomatch@^4.0.3: 2796 + version "4.0.3" 2797 + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" 2798 + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== 2799 + 3567 2800 pify@^2.3.0: 3568 2801 version "2.3.0" 3569 2802 resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" ··· 3573 2806 version "4.0.6" 3574 2807 resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" 3575 2808 integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== 3576 - 3577 - possible-typed-array-names@^1.0.0: 3578 - version "1.0.0" 3579 - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" 3580 - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== 3581 2809 3582 2810 postcss-import@^15.1.0: 3583 2811 version "15.1.0" ··· 3651 2879 resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" 3652 2880 integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== 3653 2881 3654 - prop-types@^15.8.1: 3655 - version "15.8.1" 3656 - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" 3657 - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== 3658 - dependencies: 3659 - loose-envify "^1.4.0" 3660 - object-assign "^4.1.1" 3661 - react-is "^16.13.1" 3662 - 3663 2882 punycode@^2.1.0: 3664 2883 version "2.3.1" 3665 2884 resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" ··· 3685 2904 minimist "^1.2.0" 3686 2905 strip-json-comments "~2.0.1" 3687 2906 3688 - react-is@^16.13.1: 3689 - version "16.13.1" 3690 - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" 3691 - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== 3692 - 3693 2907 read-cache@^1.0.0: 3694 2908 version "1.0.0" 3695 2909 resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" ··· 3704 2918 dependencies: 3705 2919 picomatch "^2.2.1" 3706 2920 3707 - reflect.getprototypeof@^1.0.4: 3708 - version "1.0.6" 3709 - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" 3710 - integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== 3711 - dependencies: 3712 - call-bind "^1.0.7" 3713 - define-properties "^1.2.1" 3714 - es-abstract "^1.23.1" 3715 - es-errors "^1.3.0" 3716 - get-intrinsic "^1.2.4" 3717 - globalthis "^1.0.3" 3718 - which-builtin-type "^1.1.3" 3719 - 3720 2921 regenerate-unicode-properties@^10.2.0: 3721 2922 version "10.2.0" 3722 2923 resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" ··· 3733 2934 version "0.14.1" 3734 2935 resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" 3735 2936 integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== 3736 - 3737 - regexp.prototype.flags@^1.5.2: 3738 - version "1.5.2" 3739 - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" 3740 - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== 3741 - dependencies: 3742 - call-bind "^1.0.6" 3743 - define-properties "^1.2.1" 3744 - es-errors "^1.3.0" 3745 - set-function-name "^2.0.1" 3746 2937 3747 2938 regexpu-core@^6.2.0: 3748 2939 version "6.2.0" ··· 3811 3002 path-parse "^1.0.7" 3812 3003 supports-preserve-symlinks-flag "^1.0.0" 3813 3004 3814 - resolve@^2.0.0-next.5: 3815 - version "2.0.0-next.5" 3816 - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" 3817 - integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== 3818 - dependencies: 3819 - is-core-module "^2.13.0" 3820 - path-parse "^1.0.7" 3821 - supports-preserve-symlinks-flag "^1.0.0" 3822 - 3823 3005 reusify@^1.0.4: 3824 3006 version "1.0.4" 3825 3007 resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 3826 3008 integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 3827 - 3828 - rimraf@^3.0.2: 3829 - version "3.0.2" 3830 - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 3831 - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 3832 - dependencies: 3833 - glob "^7.1.3" 3834 3009 3835 3010 rollup@^4.40.0: 3836 3011 version "4.45.0" ··· 3868 3043 dependencies: 3869 3044 queue-microtask "^1.2.2" 3870 3045 3871 - safe-array-concat@^1.1.2: 3872 - version "1.1.2" 3873 - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" 3874 - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== 3875 - dependencies: 3876 - call-bind "^1.0.7" 3877 - get-intrinsic "^1.2.4" 3878 - has-symbols "^1.0.3" 3879 - isarray "^2.0.5" 3880 - 3881 3046 safe-buffer@5.2.1, safe-buffer@^5.0.1: 3882 3047 version "5.2.1" 3883 3048 resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 3884 3049 integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 3885 3050 3886 - safe-regex-test@^1.0.3: 3887 - version "1.0.3" 3888 - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" 3889 - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== 3890 - dependencies: 3891 - call-bind "^1.0.6" 3892 - es-errors "^1.3.0" 3893 - is-regex "^1.1.4" 3894 - 3895 3051 semver@^6.3.1: 3896 3052 version "6.3.1" 3897 3053 resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" 3898 3054 integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== 3899 3055 3900 - semver@^7.3.7, semver@^7.5.4: 3901 - version "7.6.0" 3902 - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" 3903 - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== 3904 - dependencies: 3905 - lru-cache "^6.0.0" 3056 + semver@^7.7.3: 3057 + version "7.7.3" 3058 + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" 3059 + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== 3906 3060 3907 3061 serve-handler@6.1.6: 3908 3062 version "6.1.6" ··· 3934 3088 serve-handler "6.1.6" 3935 3089 update-check "1.5.4" 3936 3090 3937 - set-function-length@^1.2.1: 3938 - version "1.2.2" 3939 - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" 3940 - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== 3941 - dependencies: 3942 - define-data-property "^1.1.4" 3943 - es-errors "^1.3.0" 3944 - function-bind "^1.1.2" 3945 - get-intrinsic "^1.2.4" 3946 - gopd "^1.0.1" 3947 - has-property-descriptors "^1.0.2" 3948 - 3949 - set-function-name@^2.0.1, set-function-name@^2.0.2: 3950 - version "2.0.2" 3951 - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" 3952 - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== 3953 - dependencies: 3954 - define-data-property "^1.1.4" 3955 - es-errors "^1.3.0" 3956 - functions-have-names "^1.2.3" 3957 - has-property-descriptors "^1.0.2" 3958 - 3959 3091 shebang-command@^2.0.0: 3960 3092 version "2.0.0" 3961 3093 resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" ··· 3968 3100 resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 3969 3101 integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 3970 3102 3971 - side-channel@^1.0.4, side-channel@^1.0.6: 3972 - version "1.0.6" 3973 - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" 3974 - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== 3975 - dependencies: 3976 - call-bind "^1.0.7" 3977 - es-errors "^1.3.0" 3978 - get-intrinsic "^1.2.4" 3979 - object-inspect "^1.13.1" 3980 - 3981 3103 signal-exit@^3.0.3: 3982 3104 version "3.0.7" 3983 3105 resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" ··· 3995 3117 dependencies: 3996 3118 kolorist "^1.6.0" 3997 3119 3998 - slash@^3.0.0: 3999 - version "3.0.0" 4000 - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" 4001 - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== 4002 - 4003 3120 source-map-js@^1.2.0: 4004 3121 version "1.2.0" 4005 3122 resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" ··· 4060 3177 emoji-regex "^9.2.2" 4061 3178 strip-ansi "^7.0.1" 4062 3179 4063 - string.prototype.matchall@^4.0.10: 4064 - version "4.0.11" 4065 - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" 4066 - integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== 4067 - dependencies: 4068 - call-bind "^1.0.7" 4069 - define-properties "^1.2.1" 4070 - es-abstract "^1.23.2" 4071 - es-errors "^1.3.0" 4072 - es-object-atoms "^1.0.0" 4073 - get-intrinsic "^1.2.4" 4074 - gopd "^1.0.1" 4075 - has-symbols "^1.0.3" 4076 - internal-slot "^1.0.7" 4077 - regexp.prototype.flags "^1.5.2" 4078 - set-function-name "^2.0.2" 4079 - side-channel "^1.0.6" 4080 - 4081 - string.prototype.trim@^1.2.9: 4082 - version "1.2.9" 4083 - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" 4084 - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== 4085 - dependencies: 4086 - call-bind "^1.0.7" 4087 - define-properties "^1.2.1" 4088 - es-abstract "^1.23.0" 4089 - es-object-atoms "^1.0.0" 4090 - 4091 - string.prototype.trimend@^1.0.8: 4092 - version "1.0.8" 4093 - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" 4094 - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== 4095 - dependencies: 4096 - call-bind "^1.0.7" 4097 - define-properties "^1.2.1" 4098 - es-object-atoms "^1.0.0" 4099 - 4100 - string.prototype.trimstart@^1.0.8: 4101 - version "1.0.8" 4102 - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" 4103 - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== 4104 - dependencies: 4105 - call-bind "^1.0.7" 4106 - define-properties "^1.2.1" 4107 - es-object-atoms "^1.0.0" 4108 - 4109 3180 "strip-ansi-cjs@npm:strip-ansi@^6.0.1": 4110 3181 version "6.0.1" 4111 3182 resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" ··· 4210 3281 commander "^2.20.0" 4211 3282 source-map-support "~0.5.20" 4212 3283 4213 - text-table@^0.2.0: 4214 - version "0.2.0" 4215 - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 4216 - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== 4217 - 4218 3284 thenify-all@^1.0.0: 4219 3285 version "1.6.0" 4220 3286 resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" ··· 4237 3303 fdir "^6.4.4" 4238 3304 picomatch "^4.0.2" 4239 3305 3306 + tinyglobby@^0.2.15: 3307 + version "0.2.15" 3308 + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" 3309 + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== 3310 + dependencies: 3311 + fdir "^6.5.0" 3312 + picomatch "^4.0.3" 3313 + 4240 3314 tlds@^1.234.0: 4241 3315 version "1.252.0" 4242 3316 resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.252.0.tgz#71d9617f4ef4cc7347843bee72428e71b8b0f419" ··· 4249 3323 dependencies: 4250 3324 is-number "^7.0.0" 4251 3325 3326 + ts-api-utils@^2.4.0: 3327 + version "2.4.0" 3328 + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz#2690579f96d2790253bdcf1ca35d569ad78f9ad8" 3329 + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== 3330 + 4252 3331 ts-interface-checker@^0.1.9: 4253 3332 version "0.1.13" 4254 3333 resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" ··· 4259 3338 resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-3.1.6.tgz#da1f0b10d82237ac23422374b3fce1edb23c3ead" 4260 3339 integrity sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w== 4261 3340 4262 - tslib@^1.8.1: 4263 - version "1.14.1" 4264 - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" 4265 - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== 4266 - 4267 - tsutils@^3.21.0: 4268 - version "3.21.0" 4269 - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" 4270 - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== 4271 - dependencies: 4272 - tslib "^1.8.1" 4273 - 4274 3341 type-check@^0.4.0, type-check@~0.4.0: 4275 3342 version "0.4.0" 4276 3343 resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" ··· 4278 3345 dependencies: 4279 3346 prelude-ls "^1.2.1" 4280 3347 4281 - type-fest@^0.20.2: 4282 - version "0.20.2" 4283 - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 4284 - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 4285 - 4286 3348 type-fest@^2.13.0: 4287 3349 version "2.19.0" 4288 3350 resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" 4289 3351 integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== 4290 3352 4291 - typed-array-buffer@^1.0.2: 4292 - version "1.0.2" 4293 - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" 4294 - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== 4295 - dependencies: 4296 - call-bind "^1.0.7" 4297 - es-errors "^1.3.0" 4298 - is-typed-array "^1.1.13" 4299 - 4300 - typed-array-byte-length@^1.0.1: 4301 - version "1.0.1" 4302 - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" 4303 - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== 4304 - dependencies: 4305 - call-bind "^1.0.7" 4306 - for-each "^0.3.3" 4307 - gopd "^1.0.1" 4308 - has-proto "^1.0.3" 4309 - is-typed-array "^1.1.13" 4310 - 4311 - typed-array-byte-offset@^1.0.2: 4312 - version "1.0.2" 4313 - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" 4314 - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== 4315 - dependencies: 4316 - available-typed-arrays "^1.0.7" 4317 - call-bind "^1.0.7" 4318 - for-each "^0.3.3" 4319 - gopd "^1.0.1" 4320 - has-proto "^1.0.3" 4321 - is-typed-array "^1.1.13" 4322 - 4323 - typed-array-length@^1.0.6: 4324 - version "1.0.6" 4325 - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" 4326 - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== 3353 + typescript-eslint@^8.20.0: 3354 + version "8.52.0" 3355 + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.52.0.tgz#b8c156b6f2b4dee202a85712ff6a37f614476413" 3356 + integrity sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA== 4327 3357 dependencies: 4328 - call-bind "^1.0.7" 4329 - for-each "^0.3.3" 4330 - gopd "^1.0.1" 4331 - has-proto "^1.0.3" 4332 - is-typed-array "^1.1.13" 4333 - possible-typed-array-names "^1.0.0" 3358 + "@typescript-eslint/eslint-plugin" "8.52.0" 3359 + "@typescript-eslint/parser" "8.52.0" 3360 + "@typescript-eslint/typescript-estree" "8.52.0" 3361 + "@typescript-eslint/utils" "8.52.0" 4334 3362 4335 3363 typescript@^5.8.3: 4336 3364 version "5.8.3" ··· 4343 3371 integrity sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA== 4344 3372 dependencies: 4345 3373 multiformats "^9.4.2" 4346 - 4347 - unbox-primitive@^1.0.2: 4348 - version "1.0.2" 4349 - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" 4350 - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== 4351 - dependencies: 4352 - call-bind "^1.0.2" 4353 - has-bigints "^1.0.2" 4354 - has-symbols "^1.0.3" 4355 - which-boxed-primitive "^1.0.2" 4356 3374 4357 3375 unicode-canonical-property-names-ecmascript@^2.0.0: 4358 3376 version "2.0.1" ··· 4377 3395 resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" 4378 3396 integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== 4379 3397 4380 - update-browserslist-db@^1.0.13, update-browserslist-db@^1.1.3: 3398 + update-browserslist-db@^1.1.3: 4381 3399 version "1.1.3" 4382 3400 resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" 4383 3401 integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== ··· 4445 3463 optionalDependencies: 4446 3464 fsevents "~2.3.3" 4447 3465 4448 - which-boxed-primitive@^1.0.2: 4449 - version "1.0.2" 4450 - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" 4451 - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== 4452 - dependencies: 4453 - is-bigint "^1.0.1" 4454 - is-boolean-object "^1.1.0" 4455 - is-number-object "^1.0.4" 4456 - is-string "^1.0.5" 4457 - is-symbol "^1.0.3" 4458 - 4459 - which-builtin-type@^1.1.3: 4460 - version "1.1.3" 4461 - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" 4462 - integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== 4463 - dependencies: 4464 - function.prototype.name "^1.1.5" 4465 - has-tostringtag "^1.0.0" 4466 - is-async-function "^2.0.0" 4467 - is-date-object "^1.0.5" 4468 - is-finalizationregistry "^1.0.2" 4469 - is-generator-function "^1.0.10" 4470 - is-regex "^1.1.4" 4471 - is-weakref "^1.0.2" 4472 - isarray "^2.0.5" 4473 - which-boxed-primitive "^1.0.2" 4474 - which-collection "^1.0.1" 4475 - which-typed-array "^1.1.9" 4476 - 4477 - which-collection@^1.0.1: 4478 - version "1.0.2" 4479 - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" 4480 - integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== 4481 - dependencies: 4482 - is-map "^2.0.3" 4483 - is-set "^2.0.3" 4484 - is-weakmap "^2.0.2" 4485 - is-weakset "^2.0.3" 4486 - 4487 - which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9: 4488 - version "1.1.15" 4489 - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" 4490 - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== 4491 - dependencies: 4492 - available-typed-arrays "^1.0.7" 4493 - call-bind "^1.0.7" 4494 - for-each "^0.3.3" 4495 - gopd "^1.0.1" 4496 - has-tostringtag "^1.0.2" 4497 - 4498 3466 which@^2.0.1: 4499 3467 version "2.0.2" 4500 3468 resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" ··· 4527 3495 string-width "^5.0.1" 4528 3496 strip-ansi "^7.0.1" 4529 3497 4530 - wrappy@1: 4531 - version "1.0.2" 4532 - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 4533 - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 4534 - 4535 3498 yallist@^3.0.2: 4536 3499 version "3.1.1" 4537 3500 resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 4538 3501 integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== 4539 - 4540 - yallist@^4.0.0: 4541 - version "4.0.0" 4542 - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 4543 - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 4544 3502 4545 3503 yaml@^2.3.4: 4546 3504 version "2.4.1"
+271
eslint.config.mjs
··· 1 + // @ts-check 2 + import js from '@eslint/js' 3 + import tseslint from 'typescript-eslint' 4 + import { defineConfig } from 'eslint/config'; 5 + import react from 'eslint-plugin-react' 6 + import reactHooks from 'eslint-plugin-react-hooks' 7 + // @ts-expect-error no types 8 + import reactNative from 'eslint-plugin-react-native' 9 + // @ts-expect-error no types 10 + import reactNativeA11y from 'eslint-plugin-react-native-a11y' 11 + import simpleImportSort from 'eslint-plugin-simple-import-sort' 12 + import importX from 'eslint-plugin-import-x' 13 + import lingui from 'eslint-plugin-lingui' 14 + import reactCompiler from 'eslint-plugin-react-compiler' 15 + import bskyInternal from 'eslint-plugin-bsky-internal' 16 + import globals from 'globals' 17 + import tsParser from '@typescript-eslint/parser' 18 + 19 + export default defineConfig( 20 + /** 21 + * Global ignores 22 + */ 23 + { 24 + ignores: [ 25 + '**/__mocks__/*.ts', 26 + 'src/platform/polyfills.ts', 27 + 'src/third-party/**', 28 + 'ios/**', 29 + 'android/**', 30 + 'coverage/**', 31 + '*.lock', 32 + '.husky/**', 33 + 'patches/**', 34 + '*.html', 35 + 'bskyweb/**', 36 + 'bskyembed/**', 37 + 'src/locale/locales/_build/**', 38 + 'src/locale/locales/**/*.js', 39 + '*.e2e.ts', 40 + '*.e2e.tsx', 41 + 'eslint.config.mjs', 42 + ], 43 + }, 44 + 45 + /** 46 + * Base configurations 47 + */ 48 + js.configs.recommended, 49 + tseslint.configs.recommendedTypeChecked, 50 + reactHooks.configs.flat.recommended, 51 + // @ts-expect-error https://github.com/un-ts/eslint-plugin-import-x/issues/439 52 + importX.flatConfigs.recommended, 53 + importX.flatConfigs.typescript, 54 + importX.flatConfigs['react-native'], 55 + 56 + /** 57 + * Main configuration for all JS/TS/JSX/TSX files 58 + */ 59 + { 60 + files: ['**/*.{js,jsx,ts,tsx}'], 61 + plugins: { 62 + react, 63 + 'react-native': reactNative, 64 + 'react-native-a11y': reactNativeA11y, 65 + 'simple-import-sort': simpleImportSort, 66 + lingui, 67 + 'react-compiler': reactCompiler, 68 + 'bsky-internal': bskyInternal, 69 + }, 70 + languageOptions: { 71 + ecmaVersion: 'latest', 72 + sourceType: 'module', 73 + globals: { 74 + ...globals.browser, 75 + }, 76 + parserOptions: { 77 + parser: tsParser, 78 + projectService: true, 79 + ecmaFeatures: { 80 + jsx: true, 81 + }, 82 + }, 83 + }, 84 + settings: { 85 + react: { 86 + version: 'detect', 87 + }, 88 + componentWrapperFunctions: ['observer'], 89 + }, 90 + rules: { 91 + /** 92 + * Custom rules 93 + */ 94 + 'bsky-internal/avoid-unwrapped-text': [ 95 + 'error', 96 + { 97 + impliedTextComponents: [ 98 + 'H1', 99 + 'H2', 100 + 'H3', 101 + 'H4', 102 + 'H5', 103 + 'H6', 104 + 'P', 105 + 'Admonition', 106 + 'Admonition.Admonition', 107 + 'Toast.Action', 108 + 'AgeAssuranceAdmonition', 109 + 'Span', 110 + 'StackedButton', 111 + ], 112 + impliedTextProps: [], 113 + suggestedTextWrappers: { 114 + Button: 'ButtonText', 115 + 'ToggleButton.Button': 'ToggleButton.ButtonText', 116 + 'SegmentedControl.Item': 'SegmentedControl.ItemText', 117 + }, 118 + }, 119 + ], 120 + 'bsky-internal/use-exact-imports': 'error', 121 + 'bsky-internal/use-typed-gates': 'error', 122 + 'bsky-internal/use-prefixed-imports': 'error', 123 + 124 + /** 125 + * React & React Native 126 + */ 127 + ...react.configs.recommended.rules, 128 + ...react.configs['jsx-runtime'].rules, 129 + 'react/no-unescaped-entities': 'off', 130 + 'react/prop-types': 'off', 131 + 'react-native/no-inline-styles': 'off', 132 + ...reactNativeA11y.configs.all.rules, 133 + 'react-compiler/react-compiler': 'warn', 134 + // TODO: Fix these and set to error 135 + 'react-hooks/set-state-in-effect': 'warn', 136 + 'react-hooks/purity': 'warn', 137 + 'react-hooks/refs': 'warn', 138 + 'react-hooks/immutability': 'warn', 139 + 140 + /** 141 + * Import sorting 142 + */ 143 + 'simple-import-sort/imports': [ 144 + 'error', 145 + { 146 + groups: [ 147 + // Side effect imports. 148 + ['^\\u0000'], 149 + // Node.js builtins prefixed with `node:`. 150 + ['^node:'], 151 + // Packages. 152 + // Things that start with a letter (or digit or underscore), or `@` followed by a letter. 153 + // React/React Native prioritized, followed by expo 154 + // Followed by all packages excluding unprefixed relative ones 155 + [ 156 + '^(react\\/(.*)$)|^(react$)|^(react-native(.*)$)', 157 + '^(expo(.*)$)|^(expo$)', 158 + '^(?!(?:alf|components|lib|locale|logger|platform|screens|state|view)(?:$|\\/))@?\\w', 159 + ], 160 + // Relative imports. 161 + // Ideally, anything that starts with a dot or # 162 + // due to unprefixed relative imports being used, we whitelist the relative paths we use 163 + // (?:$|\\/) matches end of string or / 164 + [ 165 + '^(?:#\\/)?(?:lib|state|logger|platform|locale)(?:$|\\/)', 166 + '^(?:#\\/)?view(?:$|\\/)', 167 + '^(?:#\\/)?screens(?:$|\\/)', 168 + '^(?:#\\/)?alf(?:$|\\/)', 169 + '^(?:#\\/)?components(?:$|\\/)', 170 + '^#\\/', 171 + '^\\.', 172 + ], 173 + // anything else - hopefully we don't have any of these 174 + ['^'], 175 + ], 176 + }, 177 + ], 178 + 'simple-import-sort/exports': 'error', 179 + 180 + /** 181 + * Import linting 182 + */ 183 + 'import-x/consistent-type-specifier-style': ['warn', 'prefer-inline'], 184 + 'import-x/no-unresolved': ['error', { 185 + /* 186 + * The `postinstall` hook runs `compile-if-needed` locally, but not in 187 + * CI. For CI-sake, ignore this. 188 + */ 189 + ignore: ['^#\/locale\/locales\/.+\/messages'], 190 + }], 191 + 192 + /** 193 + * TypeScript-specific rules 194 + */ 195 + 'no-unused-vars': 'off', // off, we use TS-specific rule below 196 + '@typescript-eslint/no-unused-vars': [ 197 + 'error', 198 + { 199 + argsIgnorePattern: '^_', 200 + varsIgnorePattern: '^_.+', 201 + caughtErrors: 'none', 202 + ignoreRestSiblings: true, 203 + }, 204 + ], 205 + '@typescript-eslint/consistent-type-imports': [ 206 + 'warn', 207 + {prefer: 'type-imports', fixStyle: 'inline-type-imports'}, 208 + ], 209 + '@typescript-eslint/no-require-imports': 'off', 210 + '@typescript-eslint/no-unused-expressions': ['error', { 211 + allowTernary: true, 212 + }], 213 + /** 214 + * Maintain previous behavior - these are stricter in typescript-eslint 215 + * v8 `warn` ones are probably worth fixing. `off` ones are a bit too 216 + * nit-picky 217 + */ 218 + '@typescript-eslint/no-explicit-any': 'off', 219 + '@typescript-eslint/ban-ts-comment': 'off', 220 + '@typescript-eslint/no-empty-object-type': 'off', 221 + '@typescript-eslint/no-unsafe-function-type': 'off', 222 + '@typescript-eslint/no-unsafe-assignment': 'off', 223 + '@typescript-eslint/unbound-method': 'off', 224 + '@typescript-eslint/no-unsafe-argument': 'off', 225 + '@typescript-eslint/no-unsafe-return': 'off', 226 + '@typescript-eslint/no-unsafe-member-access': 'warn', 227 + '@typescript-eslint/no-unsafe-call': 'warn', 228 + '@typescript-eslint/no-floating-promises': 'warn', 229 + '@typescript-eslint/no-misused-promises': 'warn', 230 + '@typescript-eslint/require-await': 'warn', 231 + '@typescript-eslint/no-unsafe-enum-comparison': 'warn', 232 + '@typescript-eslint/no-unnecessary-type-assertion': 'warn', 233 + '@typescript-eslint/no-redundant-type-constituents': 'warn', 234 + '@typescript-eslint/no-duplicate-type-constituents': 'warn', 235 + '@typescript-eslint/no-base-to-string': 'warn', 236 + '@typescript-eslint/prefer-promise-reject-errors': 'warn', 237 + '@typescript-eslint/await-thenable': 'warn', 238 + 239 + /** 240 + * Turn off rules that we haven't enforced thus far 241 + */ 242 + 'no-empty-pattern': 'off', 243 + 'no-async-promise-executor': 'off', 244 + 'no-constant-binary-expression': 'warn', 245 + 'prefer-const': 'off', 246 + 'no-empty': 'off', 247 + 'no-unsafe-optional-chaining': 'off', 248 + 'no-prototype-builtins': 'off', 249 + 'no-var': 'off', 250 + 'prefer-rest-params': 'off', 251 + 'no-case-declarations': 'off', 252 + 'no-irregular-whitespace': 'off', 253 + 'no-useless-escape': 'off', 254 + 'no-sparse-arrays': 'off', 255 + 'no-fallthrough': 'off', 256 + 'no-control-regex': 'off', 257 + }, 258 + }, 259 + 260 + /** 261 + * Test files configuration 262 + */ 263 + { 264 + files: ['**/__tests__/**/*.{js,jsx,ts,tsx}', '**/*.test.{js,jsx,ts,tsx}'], 265 + languageOptions: { 266 + globals: { 267 + ...globals.jest, 268 + } 269 + }, 270 + }, 271 + )
+9 -15
eslint/__tests__/avoid-unwrapped-text.test.js
··· 1 1 const {RuleTester} = require('eslint') 2 + const tseslint = require('typescript-eslint') 2 3 const avoidUnwrappedText = require('../avoid-unwrapped-text') 3 4 4 5 const ruleTester = new RuleTester({ 5 - parser: require.resolve('@typescript-eslint/parser'), 6 - parserOptions: { 7 - ecmaFeatures: { 8 - jsx: true, 6 + languageOptions: { 7 + parser: tseslint.parser, 8 + parserOptions: { 9 + ecmaFeatures: { 10 + jsx: true, 11 + }, 12 + ecmaVersion: 'latest', 13 + sourceType: 'module', 9 14 }, 10 - ecmaVersion: 6, 11 - sourceType: 'module', 12 15 }, 13 16 }) 14 17 ··· 770 773 <Trans>{foo}</Trans> 771 774 </View> 772 775 `, 773 - errors: 1, 774 - }, 775 - 776 - { 777 - code: ` 778 - <View> 779 - <Trans>{'foo'}</Trans> 780 - </View> 781 - `, 782 776 errors: 1, 783 777 }, 784 778
+290 -262
eslint/avoid-unwrapped-text.js
··· 29 29 return reversedIdentifiers.reverse().join('.') 30 30 } 31 31 32 - exports.create = function create(context) { 33 - const options = context.options[0] || {} 34 - const impliedTextProps = options.impliedTextProps ?? [] 35 - const impliedTextComponents = options.impliedTextComponents ?? [] 36 - const suggestedTextWrappers = options.suggestedTextWrappers ?? {} 37 - const textProps = [...impliedTextProps] 38 - const textComponents = ['Text', ...impliedTextComponents] 32 + module.exports = { 33 + meta: { 34 + type: 'problem', 35 + docs: { 36 + description: 'Enforce text strings are wrapped in <Text> components', 37 + }, 38 + schema: [ 39 + { 40 + type: 'object', 41 + properties: { 42 + impliedTextComponents: { 43 + type: 'array', 44 + items: {type: 'string'}, 45 + }, 46 + impliedTextProps: { 47 + type: 'array', 48 + items: {type: 'string'}, 49 + }, 50 + suggestedTextWrappers: { 51 + type: 'object', 52 + additionalProperties: {type: 'string'}, 53 + }, 54 + }, 55 + additionalProperties: false, 56 + }, 57 + ], 58 + }, 59 + create(context) { 60 + const options = context.options[0] || {} 61 + const impliedTextProps = options.impliedTextProps ?? [] 62 + const impliedTextComponents = options.impliedTextComponents ?? [] 63 + const suggestedTextWrappers = options.suggestedTextWrappers ?? {} 64 + const textProps = [...impliedTextProps] 65 + const textComponents = ['Text', ...impliedTextComponents] 39 66 40 - function isTextComponent(tagName) { 41 - return textComponents.includes(tagName) || tagName.endsWith('Text') 42 - } 67 + function isTextComponent(tagName) { 68 + return textComponents.includes(tagName) || tagName.endsWith('Text') 69 + } 43 70 44 - return { 45 - JSXText(node) { 46 - if (typeof node.value !== 'string' || hasOnlyLineBreak(node.value)) { 47 - return 48 - } 49 - let parent = node.parent 50 - while (parent) { 51 - if (parent.type === 'JSXElement') { 52 - const tagName = getTagName(parent) 53 - if (isTextComponent(tagName)) { 54 - // We're good. 71 + return { 72 + JSXText(node) { 73 + if (typeof node.value !== 'string' || hasOnlyLineBreak(node.value)) { 74 + return 75 + } 76 + let parent = node.parent 77 + while (parent) { 78 + if (parent.type === 'JSXElement') { 79 + const tagName = getTagName(parent) 80 + if (isTextComponent(tagName)) { 81 + // We're good. 82 + return 83 + } 84 + if (tagName === 'Trans') { 85 + // Exit and rely on the traversal for <Trans> JSXElement (code below). 86 + // TODO: Maybe validate that it's present. 87 + return 88 + } 89 + const suggestedWrapper = suggestedTextWrappers[tagName] 90 + let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` 91 + if (tagName !== 'View' && !suggestedWrapper) { 92 + message += 93 + ' If <' + 94 + tagName + 95 + '> is guaranteed to render <Text>, ' + 96 + 'rename it to <' + 97 + tagName + 98 + 'Text> or add it to impliedTextComponents.' 99 + } 100 + context.report({ 101 + node, 102 + message, 103 + }) 55 104 return 56 105 } 57 - if (tagName === 'Trans') { 58 - // Exit and rely on the traversal for <Trans> JSXElement (code below). 59 - // TODO: Maybe validate that it's present. 106 + 107 + if ( 108 + parent.type === 'JSXAttribute' && 109 + parent.name.type === 'JSXIdentifier' && 110 + parent.parent.type === 'JSXOpeningElement' && 111 + parent.parent.parent.type === 'JSXElement' 112 + ) { 113 + const tagName = getTagName(parent.parent.parent) 114 + const propName = parent.name.name 115 + if ( 116 + textProps.includes(tagName + ' ' + propName) || 117 + propName === 'text' || 118 + propName.endsWith('Text') 119 + ) { 120 + // We're good. 121 + return 122 + } 123 + const message = 124 + 'Wrap this string in <Text>.' + 125 + ' If `' + 126 + propName + 127 + '` is guaranteed to be wrapped in <Text>, ' + 128 + 'rename it to `' + 129 + propName + 130 + 'Text' + 131 + '` or add it to impliedTextProps.' 132 + context.report({ 133 + node, 134 + message, 135 + }) 60 136 return 61 137 } 62 - const suggestedWrapper = suggestedTextWrappers[tagName] 63 - let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` 64 - if (tagName !== 'View' && !suggestedWrapper) { 65 - message += 66 - ' If <' + 67 - tagName + 68 - '> is guaranteed to render <Text>, ' + 69 - 'rename it to <' + 70 - tagName + 71 - 'Text> or add it to impliedTextComponents.' 72 - } 73 - context.report({ 74 - node, 75 - message, 76 - }) 138 + 139 + parent = parent.parent 140 + continue 141 + } 142 + }, 143 + Literal(node) { 144 + if (typeof node.value !== 'string' && typeof node.value !== 'number') { 77 145 return 78 146 } 147 + let parent = node.parent 148 + while (parent) { 149 + if (parent.type === 'JSXElement') { 150 + const tagName = getTagName(parent) 151 + if (isTextComponent(tagName)) { 152 + // We're good. 153 + return 154 + } 155 + if (tagName === 'Trans') { 156 + // Exit and rely on the traversal for <Trans> JSXElement (code below). 157 + // TODO: Maybe validate that it's present. 158 + return 159 + } 160 + const suggestedWrapper = suggestedTextWrappers[tagName] 161 + let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` 162 + if (tagName !== 'View' && !suggestedWrapper) { 163 + message += 164 + ' If <' + 165 + tagName + 166 + '> is guaranteed to render <Text>, ' + 167 + 'rename it to <' + 168 + tagName + 169 + 'Text> or add it to impliedTextComponents.' 170 + } 171 + context.report({ 172 + node, 173 + message, 174 + }) 175 + return 176 + } 79 177 80 - if ( 81 - parent.type === 'JSXAttribute' && 82 - parent.name.type === 'JSXIdentifier' && 83 - parent.parent.type === 'JSXOpeningElement' && 84 - parent.parent.parent.type === 'JSXElement' 85 - ) { 86 - const tagName = getTagName(parent.parent.parent) 87 - const propName = parent.name.name 178 + if (parent.type === 'BinaryExpression' && parent.operator === '+') { 179 + parent = parent.parent 180 + continue 181 + } 182 + 88 183 if ( 89 - textProps.includes(tagName + ' ' + propName) || 90 - propName === 'text' || 91 - propName.endsWith('Text') 184 + parent.type === 'JSXExpressionContainer' || 185 + parent.type === 'LogicalExpression' 92 186 ) { 93 - // We're good. 94 - return 187 + parent = parent.parent 188 + continue 95 189 } 96 - const message = 97 - 'Wrap this string in <Text>.' + 98 - ' If `' + 99 - propName + 100 - '` is guaranteed to be wrapped in <Text>, ' + 101 - 'rename it to `' + 102 - propName + 103 - 'Text' + 104 - '` or add it to impliedTextProps.' 105 - context.report({ 106 - node, 107 - message, 108 - }) 190 + 191 + // Be conservative for other types. 109 192 return 110 193 } 111 - 112 - parent = parent.parent 113 - continue 114 - } 115 - }, 116 - Literal(node) { 117 - if (typeof node.value !== 'string' && typeof node.value !== 'number') { 118 - return 119 - } 120 - let parent = node.parent 121 - while (parent) { 122 - if (parent.type === 'JSXElement') { 123 - const tagName = getTagName(parent) 124 - if (isTextComponent(tagName)) { 125 - // We're good. 194 + }, 195 + TemplateLiteral(node) { 196 + let parent = node.parent 197 + while (parent) { 198 + if (parent.type === 'JSXElement') { 199 + const tagName = getTagName(parent) 200 + if (isTextComponent(tagName)) { 201 + // We're good. 202 + return 203 + } 204 + if (tagName === 'Trans') { 205 + // Exit and rely on the traversal for <Trans> JSXElement (code below). 206 + // TODO: Maybe validate that it's present. 207 + return 208 + } 209 + const suggestedWrapper = suggestedTextWrappers[tagName] 210 + let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` 211 + if (tagName !== 'View' && !suggestedWrapper) { 212 + message += 213 + ' If <' + 214 + tagName + 215 + '> is guaranteed to render <Text>, ' + 216 + 'rename it to <' + 217 + tagName + 218 + 'Text> or add it to impliedTextComponents.' 219 + } 220 + context.report({ 221 + node, 222 + message, 223 + }) 126 224 return 127 225 } 128 - if (tagName === 'Trans') { 129 - // Exit and rely on the traversal for <Trans> JSXElement (code below). 130 - // TODO: Maybe validate that it's present. 131 - return 226 + 227 + if ( 228 + parent.type === 'CallExpression' && 229 + parent.callee.type === 'Identifier' && 230 + parent.callee.name === '_' 231 + ) { 232 + // This is a user-facing string, keep going up. 233 + parent = parent.parent 234 + continue 132 235 } 133 - const suggestedWrapper = suggestedTextWrappers[tagName] 134 - let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` 135 - if (tagName !== 'View' && !suggestedWrapper) { 136 - message += 137 - ' If <' + 138 - tagName + 139 - '> is guaranteed to render <Text>, ' + 140 - 'rename it to <' + 141 - tagName + 142 - 'Text> or add it to impliedTextComponents.' 236 + 237 + if (parent.type === 'BinaryExpression' && parent.operator === '+') { 238 + parent = parent.parent 239 + continue 240 + } 241 + 242 + if ( 243 + parent.type === 'JSXExpressionContainer' || 244 + parent.type === 'LogicalExpression' || 245 + parent.type === 'TaggedTemplateExpression' 246 + ) { 247 + parent = parent.parent 248 + continue 143 249 } 144 - context.report({ 145 - node, 146 - message, 147 - }) 250 + 251 + // Be conservative for other types. 148 252 return 149 253 } 150 - 151 - if (parent.type === 'BinaryExpression' && parent.operator === '+') { 152 - parent = parent.parent 153 - continue 254 + }, 255 + JSXElement(node) { 256 + if (getTagName(node) !== 'Trans') { 257 + return 154 258 } 155 - 156 - if ( 157 - parent.type === 'JSXExpressionContainer' || 158 - parent.type === 'LogicalExpression' 159 - ) { 160 - parent = parent.parent 161 - continue 162 - } 163 - 164 - // Be conservative for other types. 165 - return 166 - } 167 - }, 168 - TemplateLiteral(node) { 169 - let parent = node.parent 170 - while (parent) { 171 - if (parent.type === 'JSXElement') { 172 - const tagName = getTagName(parent) 173 - if (isTextComponent(tagName)) { 174 - // We're good. 259 + let parent = node.parent 260 + while (parent) { 261 + if (parent.type === 'JSXElement') { 262 + const tagName = getTagName(parent) 263 + if (isTextComponent(tagName)) { 264 + // We're good. 265 + return 266 + } 267 + if (tagName === 'Trans') { 268 + // Exit and rely on the traversal for this JSXElement. 269 + // TODO: Should nested <Trans> even be allowed? 270 + return 271 + } 272 + const suggestedWrapper = suggestedTextWrappers[tagName] 273 + let message = `Wrap this <Trans> in <${suggestedWrapper ?? 'Text'}>.` 274 + if (tagName !== 'View' && !suggestedWrapper) { 275 + message += 276 + ' If <' + 277 + tagName + 278 + '> is guaranteed to render <Text>, ' + 279 + 'rename it to <' + 280 + tagName + 281 + 'Text> or add it to impliedTextComponents.' 282 + } 283 + context.report({ 284 + node, 285 + message, 286 + }) 175 287 return 176 288 } 177 - if (tagName === 'Trans') { 178 - // Exit and rely on the traversal for <Trans> JSXElement (code below). 179 - // TODO: Maybe validate that it's present. 289 + 290 + if ( 291 + parent.type === 'JSXAttribute' && 292 + parent.name.type === 'JSXIdentifier' && 293 + parent.parent.type === 'JSXOpeningElement' && 294 + parent.parent.parent.type === 'JSXElement' 295 + ) { 296 + const tagName = getTagName(parent.parent.parent) 297 + const propName = parent.name.name 298 + if ( 299 + textProps.includes(tagName + ' ' + propName) || 300 + propName === 'text' || 301 + propName.endsWith('Text') 302 + ) { 303 + // We're good. 304 + return 305 + } 306 + const message = 307 + 'Wrap this <Trans> in <Text>.' + 308 + ' If `' + 309 + propName + 310 + '` is guaranteed to be wrapped in <Text>, ' + 311 + 'rename it to `' + 312 + propName + 313 + 'Text' + 314 + '` or add it to impliedTextProps.' 315 + context.report({ 316 + node, 317 + message, 318 + }) 180 319 return 181 320 } 182 - const suggestedWrapper = suggestedTextWrappers[tagName] 183 - let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` 184 - if (tagName !== 'View' && !suggestedWrapper) { 185 - message += 186 - ' If <' + 187 - tagName + 188 - '> is guaranteed to render <Text>, ' + 189 - 'rename it to <' + 190 - tagName + 191 - 'Text> or add it to impliedTextComponents.' 192 - } 193 - context.report({ 194 - node, 195 - message, 196 - }) 197 - return 198 - } 199 321 200 - if ( 201 - parent.type === 'CallExpression' && 202 - parent.callee.type === 'Identifier' && 203 - parent.callee.name === '_' 204 - ) { 205 - // This is a user-facing string, keep going up. 206 322 parent = parent.parent 207 323 continue 208 324 } 209 - 210 - if (parent.type === 'BinaryExpression' && parent.operator === '+') { 211 - parent = parent.parent 212 - continue 325 + }, 326 + ReturnStatement(node) { 327 + let fnScope = context.sourceCode.getScope(node) 328 + while (fnScope && fnScope.type !== 'function') { 329 + fnScope = fnScope.upper 213 330 } 214 - 215 - if ( 216 - parent.type === 'JSXExpressionContainer' || 217 - parent.type === 'LogicalExpression' || 218 - parent.type === 'TaggedTemplateExpression' 219 - ) { 220 - parent = parent.parent 221 - continue 331 + if (!fnScope) { 332 + return 222 333 } 223 - 224 - // Be conservative for other types. 225 - return 226 - } 227 - }, 228 - JSXElement(node) { 229 - if (getTagName(node) !== 'Trans') { 230 - return 231 - } 232 - let parent = node.parent 233 - while (parent) { 234 - if (parent.type === 'JSXElement') { 235 - const tagName = getTagName(parent) 236 - if (isTextComponent(tagName)) { 237 - // We're good. 238 - return 239 - } 240 - if (tagName === 'Trans') { 241 - // Exit and rely on the traversal for this JSXElement. 242 - // TODO: Should nested <Trans> even be allowed? 243 - return 244 - } 245 - const suggestedWrapper = suggestedTextWrappers[tagName] 246 - let message = `Wrap this <Trans> in <${suggestedWrapper ?? 'Text'}>.` 247 - if (tagName !== 'View' && !suggestedWrapper) { 248 - message += 249 - ' If <' + 250 - tagName + 251 - '> is guaranteed to render <Text>, ' + 252 - 'rename it to <' + 253 - tagName + 254 - 'Text> or add it to impliedTextComponents.' 255 - } 256 - context.report({ 257 - node, 258 - message, 259 - }) 334 + const fn = fnScope.block 335 + if (!fn.id || fn.id.type !== 'Identifier' || !fn.id.name) { 260 336 return 261 337 } 262 - 263 - if ( 264 - parent.type === 'JSXAttribute' && 265 - parent.name.type === 'JSXIdentifier' && 266 - parent.parent.type === 'JSXOpeningElement' && 267 - parent.parent.parent.type === 'JSXElement' 268 - ) { 269 - const tagName = getTagName(parent.parent.parent) 270 - const propName = parent.name.name 271 - if ( 272 - textProps.includes(tagName + ' ' + propName) || 273 - propName === 'text' || 274 - propName.endsWith('Text') 275 - ) { 276 - // We're good. 277 - return 278 - } 279 - const message = 280 - 'Wrap this <Trans> in <Text>.' + 281 - ' If `' + 282 - propName + 283 - '` is guaranteed to be wrapped in <Text>, ' + 284 - 'rename it to `' + 285 - propName + 286 - 'Text' + 287 - '` or add it to impliedTextProps.' 338 + if (!/^[A-Z]\w*Text$/.test(fn.id.name)) { 339 + return 340 + } 341 + if (!node.argument || node.argument.type !== 'JSXElement') { 342 + return 343 + } 344 + const openingEl = node.argument.openingElement 345 + if (openingEl.name.type !== 'JSXIdentifier') { 346 + return 347 + } 348 + const returnedComponentName = openingEl.name.name 349 + if (!isTextComponent(returnedComponentName)) { 288 350 context.report({ 289 351 node, 290 - message, 352 + message: 353 + 'Components ending with *Text must return <Text> or <SomeText>.', 291 354 }) 292 - return 293 355 } 294 - 295 - parent = parent.parent 296 - continue 297 - } 298 - }, 299 - ReturnStatement(node) { 300 - let fnScope = context.getScope() 301 - while (fnScope && fnScope.type !== 'function') { 302 - fnScope = fnScope.upper 303 - } 304 - if (!fnScope) { 305 - return 306 - } 307 - const fn = fnScope.block 308 - if (!fn.id || fn.id.type !== 'Identifier' || !fn.id.name) { 309 - return 310 - } 311 - if (!/^[A-Z]\w*Text$/.test(fn.id.name)) { 312 - return 313 - } 314 - if (!node.argument || node.argument.type !== 'JSXElement') { 315 - return 316 - } 317 - const openingEl = node.argument.openingElement 318 - if (openingEl.name.type !== 'JSXIdentifier') { 319 - return 320 - } 321 - const returnedComponentName = openingEl.name.name 322 - if (!isTextComponent(returnedComponentName)) { 323 - context.report({ 324 - node, 325 - message: 326 - 'Components ending with *Text must return <Text> or <SomeText>.', 327 - }) 328 - } 329 - }, 330 - } 356 + }, 357 + } 358 + }, 331 359 }
+7 -1
eslint/index.js
··· 1 1 'use strict' 2 2 3 - module.exports = { 3 + const plugin = { 4 + meta: { 5 + name: 'eslint-plugin-bsky-internal', 6 + version: '1.0.0', 7 + }, 4 8 rules: { 5 9 'avoid-unwrapped-text': require('./avoid-unwrapped-text'), 6 10 'use-exact-imports': require('./use-exact-imports'), ··· 8 12 'use-prefixed-imports': require('./use-prefixed-imports'), 9 13 }, 10 14 } 15 + 16 + module.exports = plugin
+24 -15
eslint/use-exact-imports.js
··· 3 3 '@fortawesome/free-solid-svg-icons', 4 4 ] 5 5 6 - exports.create = function create(context) { 7 - return { 8 - ImportDeclaration(node) { 9 - const source = node.source 10 - if (typeof source.value !== 'string') { 11 - return 12 - } 13 - if (BANNED_IMPORTS.includes(source.value)) { 14 - context.report({ 15 - node, 16 - message: 17 - 'Import the specific thing you want instead of the entire package', 18 - }) 19 - } 6 + module.exports = { 7 + meta: { 8 + type: 'suggestion', 9 + docs: { 10 + description: 'Prevent importing entire icon packages', 20 11 }, 21 - } 12 + schema: [], 13 + }, 14 + create(context) { 15 + return { 16 + ImportDeclaration(node) { 17 + const source = node.source 18 + if (typeof source.value !== 'string') { 19 + return 20 + } 21 + if (BANNED_IMPORTS.includes(source.value)) { 22 + context.report({ 23 + node, 24 + message: 25 + 'Import the specific thing you want instead of the entire package', 26 + }) 27 + } 28 + }, 29 + } 30 + }, 22 31 }
+4
eslint/use-prefixed-imports.js
··· 13 13 module.exports = { 14 14 meta: { 15 15 type: 'suggestion', 16 + docs: { 17 + description: 'Enforce using prefixed imports for internal paths', 18 + }, 16 19 fixable: 'code', 20 + schema: [], 17 21 }, 18 22 create(context) { 19 23 return {
+37 -27
eslint/use-typed-gates.js
··· 1 1 'use strict' 2 2 3 - exports.create = function create(context) { 4 - return { 5 - ImportSpecifier(node) { 6 - if ( 7 - !node.local || 8 - node.local.type !== 'Identifier' || 9 - node.local.name !== 'useGate' 10 - ) { 11 - return 12 - } 13 - if ( 14 - node.parent.type !== 'ImportDeclaration' || 15 - !node.parent.source || 16 - node.parent.source.type !== 'Literal' 17 - ) { 18 - return 19 - } 20 - const source = node.parent.source.value 21 - if (source.startsWith('statsig') || source.startsWith('@statsig')) { 22 - context.report({ 23 - node, 24 - message: 25 - "Use useGate() from '#/lib/statsig/statsig' instead of the one on npm.", 26 - }) 27 - } 28 - // TODO: Verify gate() call results aren't stored in variables. 3 + module.exports = { 4 + meta: { 5 + type: 'suggestion', 6 + docs: { 7 + description: 8 + 'Enforce using internal statsig wrapper instead of npm package', 29 9 }, 30 - } 10 + schema: [], 11 + }, 12 + create(context) { 13 + return { 14 + ImportSpecifier(node) { 15 + if ( 16 + !node.local || 17 + node.local.type !== 'Identifier' || 18 + node.local.name !== 'useGate' 19 + ) { 20 + return 21 + } 22 + if ( 23 + node.parent.type !== 'ImportDeclaration' || 24 + !node.parent.source || 25 + node.parent.source.type !== 'Literal' 26 + ) { 27 + return 28 + } 29 + const source = node.parent.source.value 30 + if (source.startsWith('statsig') || source.startsWith('@statsig')) { 31 + context.report({ 32 + node, 33 + message: 34 + "Use useGate() from '#/lib/statsig/statsig' instead of the one on npm.", 35 + }) 36 + } 37 + // TODO: Verify gate() call results aren't stored in variables. 38 + }, 39 + } 40 + }, 31 41 }
+5 -5
modules/bottom-sheet/src/BottomSheetNativeComponent.tsx
··· 11 11 import {useSafeAreaInsets} from 'react-native-safe-area-context' 12 12 import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core' 13 13 14 - import {isIOS} from '#/platform/detection' 14 + import {IS_IOS} from '#/env' 15 15 import { 16 16 type BottomSheetState, 17 17 type BottomSheetViewProps, ··· 30 30 31 31 const NativeModule = requireNativeModule('BottomSheet') 32 32 33 - const isIOS15 = 33 + const IS_IOS15 = 34 34 Platform.OS === 'ios' && 35 35 // semvar - can be 3 segments, so can't use Number(Platform.Version) 36 36 Number(Platform.Version.split('.').at(0)) < 16 ··· 91 91 } 92 92 93 93 let extraStyles 94 - if (isIOS15 && this.state.viewHeight) { 94 + if (IS_IOS15 && this.state.viewHeight) { 95 95 const {viewHeight} = this.state 96 96 const cornerRadius = this.props.cornerRadius ?? 0 97 97 if (viewHeight < screenHeight / 2) { ··· 112 112 onStateChange={this.onStateChange} 113 113 extraStyles={extraStyles} 114 114 onLayout={e => { 115 - if (isIOS15) { 115 + if (IS_IOS15) { 116 116 const {height} = e.nativeEvent.layout 117 117 this.setState({viewHeight: height}) 118 118 } ··· 153 153 const insets = useSafeAreaInsets() 154 154 const cornerRadius = rest.cornerRadius ?? 0 155 155 156 - const sheetHeight = isIOS ? screenHeight - insets.top : screenHeight 156 + const sheetHeight = IS_IOS ? screenHeight - insets.top : screenHeight 157 157 158 158 return ( 159 159 <NativeView
+13 -11
package.json
··· 41 41 "test-watch": "NODE_ENV=test jest --watchAll", 42 42 "test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit", 43 43 "test-coverage": "NODE_ENV=test jest --coverage", 44 - "lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src", 44 + "lint": "eslint --cache --quiet src", 45 45 "lint-native": "swiftlint ./modules && ktlint ./modules", 46 46 "lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules", 47 47 "typecheck": "tsc --project ./tsconfig.check.json", ··· 232 232 "@babel/core": "^7.26.0", 233 233 "@babel/preset-env": "^7.26.0", 234 234 "@babel/runtime": "^7.26.0", 235 + "@eslint/js": "^9.39.2", 235 236 "@expo/config-plugins": "~54.0.1", 236 237 "@lingui/cli": "^4.14.1", 237 238 "@lingui/macro": "^4.14.1", ··· 251 252 "@types/psl": "^1.1.1", 252 253 "@types/react": "^19.1.12", 253 254 "@types/react-dom": "^19.1.9", 254 - "@typescript-eslint/eslint-plugin": "^7.18.0", 255 - "@typescript-eslint/parser": "^7.18.0", 256 255 "babel-jest": "^29.7.0", 257 256 "babel-plugin-macros": "^3.1.0", 258 257 "babel-plugin-module-resolver": "^5.0.2", 259 258 "babel-plugin-react-compiler": "^19.1.0-rc.3", 260 259 "babel-preset-expo": "~54.0.0", 261 - "eslint": "^8.19.0", 260 + "eslint": "^9.39.2", 261 + "eslint-import-resolver-typescript": "^4.4.4", 262 262 "eslint-plugin-bsky-internal": "link:./eslint", 263 - "eslint-plugin-ft-flow": "^2.0.3", 264 - "eslint-plugin-import": "^2.31.0", 265 - "eslint-plugin-lingui": "^0.2.0", 266 - "eslint-plugin-react": "^7.33.2", 263 + "eslint-plugin-import-x": "^4.16.1", 264 + "eslint-plugin-lingui": "^0.11.0", 265 + "eslint-plugin-react": "^7.37.5", 267 266 "eslint-plugin-react-compiler": "^19.1.0-rc.2", 268 - "eslint-plugin-react-native-a11y": "^3.3.0", 269 - "eslint-plugin-simple-import-sort": "^12.0.0", 267 + "eslint-plugin-react-hooks": "^7.0.1", 268 + "eslint-plugin-react-native": "^5.0.0", 269 + "eslint-plugin-react-native-a11y": "^3.5.1", 270 + "eslint-plugin-simple-import-sort": "^12.1.1", 270 271 "file-loader": "6.2.0", 272 + "globals": "^17.0.0", 271 273 "husky": "^8.0.3", 272 274 "is-ci": "^3.0.1", 273 275 "jest": "^29.7.0", ··· 282 284 "ts-node": "^10.9.1", 283 285 "ts-plugin-sort-import-suggestions": "^1.0.4", 284 286 "typescript": "^5.9.2", 287 + "typescript-eslint": "^8.53.0", 285 288 "webpack-bundle-analyzer": "^4.10.1" 286 289 }, 287 290 "resolutions": { ··· 291 294 "**/@react-native-async-storage/async-storage": "2.2.0", 292 295 "**/expo-constants": "18.0.8", 293 296 "**/expo-device": "7.1.4", 294 - "**/zod": "3.23.8", 295 297 "**/multiformats": "9.9.0", 296 298 "unicode-segmenter": "0.14.5" 297 299 },
+3 -3
src/App.native.tsx
··· 23 23 import {ThemeProvider} from '#/lib/ThemeContext' 24 24 import I18nProvider from '#/locale/i18nProvider' 25 25 import {logger} from '#/logger' 26 - import {isAndroid, isIOS} from '#/platform/detection' 27 26 import {Provider as A11yProvider} from '#/state/a11y' 28 27 import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' 29 28 import {Provider as DialogStateProvider} from '#/state/dialogs' ··· 69 68 import {ToastOutlet} from '#/components/Toast' 70 69 import {Provider as AgeAssuranceV2Provider} from '#/ageAssurance' 71 70 import {prefetchAgeAssuranceConfig} from '#/ageAssurance' 71 + import {IS_ANDROID, IS_IOS} from '#/env' 72 72 import { 73 73 prefetchLiveEvents, 74 74 Provider as LiveEventsProvider, ··· 79 79 import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' 80 80 81 81 SplashScreen.preventAutoHideAsync() 82 - if (isIOS) { 82 + if (IS_IOS) { 83 83 SystemUI.setBackgroundColorAsync('black') 84 84 } 85 - if (isAndroid) { 85 + if (IS_ANDROID) { 86 86 // iOS is handled by the config plugin -sfn 87 87 ScreenOrientation.lockAsync( 88 88 ScreenOrientation.OrientationLock.PORTRAIT_UP,
+6 -6
src/Navigation.tsx
··· 44 44 import {attachRouteToLogEvents, logEvent} from '#/lib/statsig/statsig' 45 45 import {bskyTitle} from '#/lib/strings/headings' 46 46 import {logger} from '#/logger' 47 - import {isNative, isWeb} from '#/platform/detection' 48 47 import {useDisableVerifyEmailReminder} from '#/state/preferences/disable-verify-email-reminder' 49 48 import {useUnreadNotifications} from '#/state/queries/notifications/unread' 50 49 import {useSession} from '#/state/session' ··· 140 139 EmailDialogScreenID, 141 140 useEmailDialogControl, 142 141 } from '#/components/dialogs/EmailDialog' 142 + import {IS_NATIVE, IS_WEB} from '#/env' 143 143 import {router} from '#/routes' 144 144 import {Referrer} from '../modules/expo-bluesky-swiss-army' 145 145 ··· 852 852 // native, since the home tab and the home screen are defined as initial routes, we don't need to return a state 853 853 // since it will be created by react-navigation. 854 854 if (path.includes('intent/')) { 855 - if (isNative) return 855 + if (IS_NATIVE) return 856 856 return buildStateObject('Flat', 'Home', params) 857 857 } 858 858 859 - if (isNative) { 859 + if (IS_NATIVE) { 860 860 if (name === 'Search') { 861 861 return buildStateObject('SearchTab', 'Search', params) 862 862 } ··· 933 933 ) 934 934 935 935 async function handlePushNotificationEntry() { 936 - if (!isNative) return 936 + if (!IS_NATIVE) return 937 937 938 938 // deep links take precedence - on android, 939 939 // getLastNotificationResponseAsync returns a "notification" ··· 1085 1085 navigationRef.dispatch( 1086 1086 CommonActions.reset({ 1087 1087 index: 0, 1088 - routes: [{name: isNative ? 'HomeTab' : 'Home'}], 1088 + routes: [{name: IS_NATIVE ? 'HomeTab' : 'Home'}], 1089 1089 }), 1090 1090 ) 1091 1091 return Promise.race([ ··· 1119 1119 initMs, 1120 1120 }) 1121 1121 1122 - if (isWeb) { 1122 + if (IS_WEB) { 1123 1123 const referrerInfo = Referrer.getReferrerInfo() 1124 1124 if (referrerInfo && referrerInfo.hostname !== 'bsky.app') { 1125 1125 logEvent('deepLink:referrerReceived', {
+5 -5
src/ageAssurance/components/NoAccessScreen.tsx
··· 10 10 } from '#/lib/hooks/useCreateSupportLink' 11 11 import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 12 12 import {logger} from '#/logger' 13 - import {isWeb} from '#/platform/detection' 14 - import {isNative} from '#/platform/detection' 15 13 import {useIsBirthdateUpdateAllowed} from '#/state/birthdate' 16 14 import {useSessionApi} from '#/state/session' 17 15 import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' ··· 38 36 isLegacyBirthdateBug, 39 37 useAgeAssuranceRegionConfig, 40 38 } from '#/ageAssurance/util' 39 + import {IS_WEB} from '#/env' 40 + import {IS_NATIVE} from '#/env' 41 41 import {useDeviceGeolocationApi} from '#/geolocation' 42 42 43 43 const textStyles = [a.text_md, a.leading_snug] ··· 74 74 }, []) 75 75 76 76 const onPressLogout = useCallback(() => { 77 - if (isWeb) { 77 + if (IS_WEB) { 78 78 // We're switching accounts, which remounts the entire app. 79 79 // On mobile, this gets us Home, but on the web we also need reset the URL. 80 80 // We can't change the URL via a navigate() call because the navigator ··· 139 139 contentContainerStyle={[ 140 140 a.px_2xl, 141 141 { 142 - paddingTop: isWeb 142 + paddingTop: IS_WEB 143 143 ? a.p_5xl.padding 144 144 : insets.top + a.p_2xl.padding, 145 145 paddingBottom: 100, ··· 359 359 )} 360 360 361 361 <View style={[a.gap_xs]}> 362 - {isNative && ( 362 + {IS_NATIVE && ( 363 363 <> 364 364 <Admonition> 365 365 <Trans>
+4 -4
src/ageAssurance/components/RedirectOverlay.tsx
··· 15 15 import {retry} from '#/lib/async/retry' 16 16 import {wait} from '#/lib/async/wait' 17 17 import {parseLinkingUrl} from '#/lib/parseLinkingUrl' 18 - import {isWeb} from '#/platform/detection' 19 - import {isIOS} from '#/platform/detection' 20 18 import {useAgent, useSession} from '#/state/session' 21 19 import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf' 22 20 import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' ··· 28 26 import {Text} from '#/components/Typography' 29 27 import {refetchAgeAssuranceServerState} from '#/ageAssurance' 30 28 import {logger} from '#/ageAssurance' 29 + import {IS_WEB} from '#/env' 30 + import {IS_IOS} from '#/env' 31 31 32 32 export type RedirectOverlayState = { 33 33 result: 'success' | 'unknown' ··· 92 92 actorDid: params.get('actorDid') ?? undefined, 93 93 }) 94 94 95 - if (isWeb) { 95 + if (IS_WEB) { 96 96 // Clear the URL parameters so they don't re-trigger 97 97 history.pushState(null, '', '/') 98 98 } ··· 149 149 // setting a zIndex when using FullWindowOverlay on iOS 150 150 // means the taps pass straight through to the underlying content (???) 151 151 // so don't set it on iOS. FullWindowOverlay already does the job. 152 - !isIOS && {zIndex: 9999}, 152 + !IS_IOS && {zIndex: 9999}, 153 153 t.atoms.bg, 154 154 gtMobile ? a.p_2xl : a.p_xl, 155 155 a.align_center,
+4 -4
src/alf/fonts.ts
··· 1 1 import {type TextStyle} from 'react-native' 2 2 3 - import {isAndroid, isWeb} from '#/platform/detection' 3 + import {IS_ANDROID, IS_WEB} from '#/env' 4 4 import {type Device, device} from '#/storage' 5 5 6 6 const WEB_FONT_FAMILIES = `system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"` ··· 39 39 */ 40 40 export function applyFonts(style: TextStyle, fontFamily: 'system' | 'theme') { 41 41 if (fontFamily === 'theme') { 42 - if (isAndroid) { 42 + if (IS_ANDROID) { 43 43 style.fontFamily = 44 44 { 45 45 400: 'Inter-Regular', ··· 71 71 } 72 72 } 73 73 74 - if (isWeb) { 74 + if (IS_WEB) { 75 75 // fallback families only supported on web 76 76 style.fontFamily += `, ${WEB_FONT_FAMILIES}` 77 77 } ··· 83 83 style.fontVariant = (style.fontVariant || []).concat('no-contextual') 84 84 } else { 85 85 // fallback families only supported on web 86 - if (isWeb) { 86 + if (IS_WEB) { 87 87 style.fontFamily = style.fontFamily || WEB_FONT_FAMILIES 88 88 } 89 89
+4 -4
src/alf/typography.tsx
··· 4 4 import {UITextView} from 'react-native-uitextview' 5 5 import createEmojiRegex from 'emoji-regex' 6 6 7 - import {isNative} from '#/platform/detection' 8 - import {isIOS} from '#/platform/detection' 9 7 import {type Alf, applyFonts, atoms, flatten} from '#/alf' 8 + import {IS_NATIVE} from '#/env' 9 + import {IS_IOS} from '#/env' 10 10 11 11 /** 12 12 * Ensures that `lineHeight` defaults to a relative value of `1`, or applies ··· 34 34 if (s.lineHeight !== 0 && s.lineHeight <= 2) { 35 35 s.lineHeight = Math.round(s.fontSize * s.lineHeight) 36 36 } 37 - } else if (!isNative) { 37 + } else if (!IS_NATIVE) { 38 38 s.lineHeight = s.fontSize 39 39 } 40 40 ··· 81 81 props: Omit<TextProps, 'children'> = {}, 82 82 emoji: boolean, 83 83 ) { 84 - if (!isIOS || !emoji) { 84 + if (!IS_IOS || !emoji) { 85 85 return children 86 86 } 87 87 return Children.map(children, child => {
+2 -2
src/alf/util/systemUI.ts
··· 2 2 import {type Theme} from '@bsky.app/alf' 3 3 4 4 import {logger} from '#/logger' 5 - import {isAndroid} from '#/platform/detection' 5 + import {IS_ANDROID} from '#/env' 6 6 7 7 export function setSystemUITheme(themeType: 'theme' | 'lightbox', t: Theme) { 8 - if (isAndroid) { 8 + if (IS_ANDROID) { 9 9 try { 10 10 if (themeType === 'theme') { 11 11 SystemUI.setBackgroundColorAsync(t.atoms.bg.backgroundColor)
+2 -2
src/alf/util/useColorModeTheme.ts
··· 2 2 import {type ColorSchemeName, useColorScheme} from 'react-native' 3 3 import {type ThemeName} from '@bsky.app/alf' 4 4 5 - import {isWeb} from '#/platform/detection' 6 5 import {useThemePrefs} from '#/state/shell' 7 6 import {dark, dim, light} from '#/alf/themes' 7 + import {IS_WEB} from '#/env' 8 8 9 9 export function useColorModeTheme(): ThemeName { 10 10 const theme = useThemeName() ··· 40 40 41 41 function updateDocument(theme: ThemeName) { 42 42 // @ts-ignore web only 43 - if (isWeb && typeof window !== 'undefined') { 43 + if (IS_WEB && typeof window !== 'undefined') { 44 44 // @ts-ignore web only 45 45 const html = window.document.documentElement 46 46 // @ts-ignore web only
+4 -4
src/components/BlockedGeoOverlay.tsx
··· 5 5 import {useLingui} from '@lingui/react' 6 6 7 7 import {logger} from '#/logger' 8 - import {isWeb} from '#/platform/detection' 9 - import {useDeviceGeolocationApi} from '#/state/geolocation' 8 + import {useDeviceGeolocationApi} from '#/geolocation' 10 9 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 11 10 import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' 12 11 import {Button, ButtonIcon, ButtonText} from '#/components/Button' ··· 20 19 import * as Toast from '#/components/Toast' 21 20 import {Text} from '#/components/Typography' 22 21 import {BottomSheetOutlet} from '#/../modules/bottom-sheet' 22 + import {IS_WEB} from '#/env' 23 23 24 24 export function BlockedGeoOverlay() { 25 25 const t = useTheme() ··· 70 70 contentContainerStyle={[ 71 71 a.px_2xl, 72 72 { 73 - paddingTop: isWeb ? a.p_5xl.padding : insets.top + a.p_2xl.padding, 73 + paddingTop: IS_WEB ? a.p_5xl.padding : insets.top + a.p_2xl.padding, 74 74 paddingBottom: 100, 75 75 }, 76 76 ]}> ··· 117 117 ))} 118 118 </View> 119 119 120 - {!isWeb && ( 120 + {!IS_WEB && ( 121 121 <> 122 122 <View style={[a.pt_2xl]}> 123 123 <Divider />
+5 -5
src/components/ContextMenu/index.tsx
··· 49 49 import {useHaptics} from '#/lib/haptics' 50 50 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 51 51 import {logger} from '#/logger' 52 - import {isAndroid, isIOS} from '#/platform/detection' 53 52 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 54 53 import {atoms as a, platform, tokens, useTheme} from '#/alf' 55 54 import { ··· 72 71 import {useInteractionState} from '#/components/hooks/useInteractionState' 73 72 import {createPortalGroup} from '#/components/Portal' 74 73 import {Text} from '#/components/Typography' 74 + import {IS_ANDROID, IS_IOS} from '#/env' 75 75 import {Backdrop} from './Backdrop' 76 76 77 77 export { ··· 82 82 const {Provider: PortalProvider, Outlet, Portal} = createPortalGroup() 83 83 84 84 const SPRING_IN: WithSpringConfig = { 85 - mass: isIOS ? 1.25 : 0.75, 85 + mass: IS_IOS ? 1.25 : 0.75, 86 86 damping: 50, 87 87 stiffness: 1100, 88 88 restDisplacementThreshold: 0.01, 89 89 } 90 90 91 91 const SPRING_OUT: WithSpringConfig = { 92 - mass: isIOS ? 1.25 : 0.75, 92 + mass: IS_IOS ? 1.25 : 0.75, 93 93 damping: 150, 94 94 stiffness: 1000, 95 95 restDisplacementThreshold: 0.01, ··· 210 210 ) 211 211 212 212 useEffect(() => { 213 - if (isAndroid && context.isOpen) { 213 + if (IS_ANDROID && context.isOpen) { 214 214 const listener = BackHandler.addEventListener('hardwareBackPress', () => { 215 215 context.close() 216 216 return true ··· 332 332 <GestureDetector gesture={composedGestures}> 333 333 <View ref={ref} style={[{opacity: context.isOpen ? 0 : 1}, style]}> 334 334 {children({ 335 - isNative: true, 335 + IS_NATIVE: true, 336 336 control: {isOpen: context.isOpen, open}, 337 337 state: { 338 338 pressed: false,
+2 -2
src/components/ContextMenu/types.ts
··· 85 85 } 86 86 export type TriggerChildProps = 87 87 | { 88 - isNative: true 88 + IS_NATIVE: true 89 89 control: { 90 90 isOpen: boolean 91 91 open: (mode: 'full' | 'auxiliary-only') => void ··· 115 115 } 116 116 } 117 117 | { 118 - isNative: false 118 + IS_NATIVE: false 119 119 control: Dialog.DialogOuterProps['control'] 120 120 state: { 121 121 hovered: false
+1 -1
src/components/Dialog/context.ts
··· 18 18 19 19 export const Context = createContext<DialogContextProps>({ 20 20 close: () => {}, 21 - isNativeDialog: false, 21 + IS_NATIVEDialog: false, 22 22 nativeSnapPoint: BottomSheetSnapPoint.Hidden, 23 23 disableDrag: false, 24 24 setDisableDrag: () => {},
+11 -11
src/components/Dialog/index.tsx
··· 26 26 import {useEnableKeyboardController} from '#/lib/hooks/useEnableKeyboardController' 27 27 import {ScrollProvider} from '#/lib/ScrollContext' 28 28 import {logger} from '#/logger' 29 - import {isAndroid, isIOS} from '#/platform/detection' 30 29 import {useA11y} from '#/state/a11y' 31 30 import {useDialogStateControlContext} from '#/state/dialogs' 32 31 import {List, type ListMethods, type ListProps} from '#/view/com/util/List' ··· 39 38 type DialogOuterProps, 40 39 } from '#/components/Dialog/types' 41 40 import {createInput} from '#/components/forms/TextField' 41 + import {IS_ANDROID, IS_IOS} from '#/env' 42 42 import {BottomSheet, BottomSheetSnapPoint} from '../../../modules/bottom-sheet' 43 43 import { 44 44 type BottomSheetSnapPointChangeEvent, ··· 154 154 const context = React.useMemo( 155 155 () => ({ 156 156 close, 157 - isNativeDialog: true, 157 + IS_NATIVEDialog: true, 158 158 nativeSnapPoint: snapPoint, 159 159 disableDrag, 160 160 setDisableDrag, ··· 209 209 const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext() 210 210 const insets = useSafeAreaInsets() 211 211 212 - useEnableKeyboardController(isIOS) 212 + useEnableKeyboardController(IS_IOS) 213 213 214 214 const [keyboardHeight, setKeyboardHeight] = React.useState(0) 215 215 ··· 224 224 ) 225 225 226 226 let paddingBottom = 0 227 - if (isIOS) { 227 + if (IS_IOS) { 228 228 paddingBottom += keyboardHeight / 4 229 229 if (nativeSnapPoint === BottomSheetSnapPoint.Full) { 230 230 paddingBottom += insets.bottom + tokens.space.md ··· 240 240 } 241 241 242 242 const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => { 243 - if (!isAndroid) { 243 + if (!IS_ANDROID) { 244 244 return 245 245 } 246 246 const {contentOffset} = e.nativeEvent ··· 260 260 contentContainerStyle, 261 261 ]} 262 262 ref={ref} 263 - showsVerticalScrollIndicator={isAndroid ? false : undefined} 263 + showsVerticalScrollIndicator={IS_ANDROID ? false : undefined} 264 264 {...props} 265 265 bounces={nativeSnapPoint === BottomSheetSnapPoint.Full} 266 266 bottomOffset={30} 267 267 scrollEventThrottle={50} 268 - onScroll={isAndroid ? onScroll : undefined} 268 + onScroll={IS_ANDROID ? onScroll : undefined} 269 269 keyboardShouldPersistTaps="handled" 270 270 // TODO: figure out why this positions the header absolutely (rather than stickily) 271 271 // on Android. fine to disable for now, because we don't have any ··· 289 289 const insets = useSafeAreaInsets() 290 290 const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext() 291 291 292 - useEnableKeyboardController(isIOS) 292 + useEnableKeyboardController(IS_IOS) 293 293 294 294 const onScroll = (e: ScrollEvent) => { 295 295 'worklet' 296 - if (!isAndroid) { 296 + if (!IS_ANDROID) { 297 297 return 298 298 } 299 299 const {contentOffset} = e ··· 311 311 bounces={nativeSnapPoint === BottomSheetSnapPoint.Full} 312 312 ListFooterComponent={<View style={{height: insets.bottom + 100}} />} 313 313 ref={ref} 314 - showsVerticalScrollIndicator={isAndroid ? false : undefined} 314 + showsVerticalScrollIndicator={IS_ANDROID ? false : undefined} 315 315 {...props} 316 316 style={[a.h_full, style]} 317 317 /> ··· 326 326 const {height} = useReanimatedKeyboardAnimation() 327 327 328 328 const animatedStyle = useAnimatedStyle(() => { 329 - if (!isIOS) return {} 329 + if (!IS_IOS) return {} 330 330 return { 331 331 transform: [{translateY: Math.min(0, height.get() + bottom - 10)}], 332 332 }
+1 -1
src/components/Dialog/index.web.tsx
··· 99 99 const context = React.useMemo( 100 100 () => ({ 101 101 close, 102 - isNativeDialog: false, 102 + IS_NATIVEDialog: false, 103 103 nativeSnapPoint: 0, 104 104 disableDrag: false, 105 105 setDisableDrag: () => {},
+2 -2
src/components/Dialog/sheet-wrapper.ts
··· 1 1 import {useCallback} from 'react' 2 2 import {SystemBars} from 'react-native-edge-to-edge' 3 3 4 - import {isIOS} from '#/platform/detection' 4 + import {IS_IOS} from '#/env' 5 5 6 6 /** 7 7 * If we're calling a system API like the image picker that opens a sheet ··· 9 9 */ 10 10 export function useSheetWrapper() { 11 11 return useCallback(async <T>(promise: Promise<T>): Promise<T> => { 12 - if (isIOS) { 12 + if (IS_IOS) { 13 13 const entry = SystemBars.pushStackEntry({ 14 14 style: { 15 15 statusBar: 'light',
+1 -1
src/components/Dialog/types.ts
··· 39 39 40 40 export type DialogContextProps = { 41 41 close: DialogControlProps['close'] 42 - isNativeDialog: boolean 42 + IS_NATIVEDialog: boolean 43 43 nativeSnapPoint: BottomSheetSnapPoint 44 44 disableDrag: boolean 45 45 setDisableDrag: React.Dispatch<React.SetStateAction<boolean>>
+3 -3
src/components/FeedInterstitials.tsx
··· 10 10 import {logEvent, useGate} from '#/lib/statsig/statsig' 11 11 import {logger} from '#/logger' 12 12 import {type MetricEvents} from '#/logger/metrics' 13 - import {isIOS} from '#/platform/detection' 14 13 import {useHideSimilarAccountsRecomm} from '#/state/preferences/hide-similar-accounts-recommendations' 15 14 import {useModerationOpts} from '#/state/preferences/moderation-opts' 16 15 import {useGetPopularFeedsQuery} from '#/state/queries/feed' ··· 40 39 import {InlineLinkText} from '#/components/Link' 41 40 import * as ProfileCard from '#/components/ProfileCard' 42 41 import {Text} from '#/components/Typography' 42 + import {IS_IOS} from '#/env' 43 43 import type * as bsky from '#/types/bsky' 44 44 import {FollowDialogWithoutGuide} from './ProgressGuide/FollowDialog' 45 45 import {ProgressGuideList} from './ProgressGuide/List' ··· 697 697 t.atoms.border_contrast_low, 698 698 t.atoms.bg_contrast_25, 699 699 ]} 700 - pointerEvents={isIOS ? 'auto' : 'box-none'}> 700 + pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 701 701 <View 702 702 style={[ 703 703 a.px_lg, ··· 706 706 a.align_center, 707 707 a.justify_between, 708 708 ]} 709 - pointerEvents={isIOS ? 'auto' : 'box-none'}> 709 + pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 710 710 <Text style={[a.text_sm, a.font_semi_bold, t.atoms.text]}> 711 711 {isFeedContext ? ( 712 712 <Trans>Suggested for you</Trans>
+3 -3
src/components/InterestTabs.tsx
··· 9 9 import {useLingui} from '@lingui/react' 10 10 11 11 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 12 - import {isWeb} from '#/platform/detection' 13 12 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 14 13 import {DraggableScrollView} from '#/view/com/pager/DraggableScrollView' 15 14 import {atoms as a, tokens, useTheme, web} from '#/alf' ··· 20 19 ArrowRight_Stroke2_Corner0_Rounded as ArrowRight, 21 20 } from '#/components/icons/Arrow' 22 21 import {Text} from '#/components/Typography' 22 + import {IS_WEB} from '#/env' 23 23 24 24 /** 25 25 * Tab component that automatically scrolls the selected tab into view - used for interests ··· 239 239 ) 240 240 })} 241 241 </DraggableScrollView> 242 - {isWeb && canScrollLeft && ( 242 + {IS_WEB && canScrollLeft && ( 243 243 <View 244 244 style={[ 245 245 a.absolute, ··· 273 273 </Button> 274 274 </View> 275 275 )} 276 - {isWeb && canScrollRight && ( 276 + {IS_WEB && canScrollRight && ( 277 277 <View 278 278 style={[ 279 279 a.absolute,
+3 -3
src/components/InternationalPhoneCodeSelect.tsx
··· 10 10 INTERNATIONAL_TELEPHONE_CODES, 11 11 } from '#/lib/international-telephone-codes' 12 12 import {regionName} from '#/locale/helpers' 13 - import {isWeb} from '#/platform/detection' 14 13 import {atoms as a, web} from '#/alf' 15 14 import * as Select from '#/components/Select' 15 + import {IS_WEB} from '#/env' 16 16 import {useGeolocation} from '#/geolocation' 17 17 18 18 /** ··· 84 84 <Select.Item value={item.value} label={item.label}> 85 85 <Select.ItemIndicator /> 86 86 <Select.ItemText style={[a.flex_1]} emoji> 87 - {isWeb ? <Flag {...item} /> : item.unicodeFlag + ' '} 87 + {IS_WEB ? <Flag {...item} /> : item.unicodeFlag + ' '} 88 88 {item.name} 89 89 </Select.ItemText> 90 90 <Select.ItemText style={[a.text_right]}> ··· 101 101 } 102 102 103 103 function Flag({unicodeFlag, svgFlag}: {unicodeFlag: string; svgFlag: any}) { 104 - if (isWeb) { 104 + if (IS_WEB) { 105 105 return ( 106 106 <Image 107 107 source={svgFlag}
+4 -4
src/components/Layout/Header/index.tsx
··· 6 6 7 7 import {HITSLOP_30} from '#/lib/constants' 8 8 import {type NavigationProp} from '#/lib/routes/types' 9 - import {isIOS} from '#/platform/detection' 10 9 import {useSetDrawerOpen} from '#/state/shell' 11 10 import { 12 11 atoms as a, ··· 29 28 } from '#/components/Layout/const' 30 29 import {ScrollbarOffsetContext} from '#/components/Layout/context' 31 30 import {Text} from '#/components/Typography' 31 + import {IS_IOS} from '#/env' 32 32 33 33 export function Outer({ 34 34 children, ··· 91 91 style={[ 92 92 a.flex_1, 93 93 a.justify_center, 94 - isIOS && align === 'platform' && a.align_center, 94 + IS_IOS && align === 'platform' && a.align_center, 95 95 {minHeight: HEADER_SLOT_SIZE}, 96 96 ]}> 97 97 <AlignmentContext.Provider value={align}> ··· 186 186 a.text_lg, 187 187 a.font_semi_bold, 188 188 a.leading_tight, 189 - isIOS && align === 'platform' && a.text_center, 189 + IS_IOS && align === 'platform' && a.text_center, 190 190 gtMobile && a.text_xl, 191 191 style, 192 192 ]} ··· 205 205 style={[ 206 206 a.text_sm, 207 207 a.leading_snug, 208 - isIOS && align === 'platform' && a.text_center, 208 + IS_IOS && align === 'platform' && a.text_center, 209 209 t.atoms.text_contrast_medium, 210 210 ]} 211 211 numberOfLines={2}>
+4 -4
src/components/Layout/index.tsx
··· 11 11 } from 'react-native-reanimated' 12 12 import {useSafeAreaInsets} from 'react-native-safe-area-context' 13 13 14 - import {isWeb} from '#/platform/detection' 15 14 import {useShellLayout} from '#/state/shell/shell-layout' 16 15 import { 17 16 atoms as a, ··· 23 22 import {useDialogContext} from '#/components/Dialog' 24 23 import {CENTER_COLUMN_OFFSET, SCROLLBAR_OFFSET} from '#/components/Layout/const' 25 24 import {ScrollbarOffsetContext} from '#/components/Layout/context' 25 + import {IS_WEB} from '#/env' 26 26 27 27 export * from '#/components/Layout/const' 28 28 export * as Header from '#/components/Layout/Header' ··· 43 43 const {top} = useSafeAreaInsets() 44 44 return ( 45 45 <> 46 - {isWeb && <WebCenterBorders />} 46 + {IS_WEB && <WebCenterBorders />} 47 47 <View 48 48 style={[a.util_screen_outer, {paddingTop: noInsetTop ? 0 : top}, style]} 49 49 {...props} ··· 98 98 contentContainerStyle, 99 99 ]} 100 100 {...props}> 101 - {isWeb ? ( 101 + {IS_WEB ? ( 102 102 <Center ignoreTabletLayoutOffset={ignoreTabletLayoutOffset}> 103 103 {/* @ts-expect-error web only -esb */} 104 104 {children} ··· 145 145 ]} 146 146 keyboardShouldPersistTaps="handled" 147 147 {...props}> 148 - {isWeb ? <Center>{children}</Center> : children} 148 + {IS_WEB ? <Center>{children}</Center> : children} 149 149 </KeyboardAwareScrollView> 150 150 ) 151 151 })
+11 -11
src/components/Link.tsx
··· 18 18 isExternalUrl, 19 19 linkRequiresWarning, 20 20 } from '#/lib/strings/url-helpers' 21 - import {isNative, isWeb} from '#/platform/detection' 22 21 import {useModalControls} from '#/state/modals' 23 22 import {useGoLinksEnabled} from '#/state/preferences' 24 23 import {atoms as a, flatten, type TextStyleProp, useTheme, web} from '#/alf' 25 24 import {Button, type ButtonProps} from '#/components/Button' 26 25 import {useInteractionState} from '#/components/hooks/useInteractionState' 27 26 import {Text, type TextProps} from '#/components/Typography' 27 + import {IS_NATIVE, IS_WEB} from '#/env' 28 28 import {router} from '#/routes' 29 29 import {useGlobalDialogsControlContext} from './dialogs/Context' 30 30 ··· 133 133 linkRequiresWarning(href, displayText), 134 134 ) 135 135 136 - if (isWeb) { 136 + if (IS_WEB) { 137 137 e.preventDefault() 138 138 } 139 139 ··· 166 166 ] 167 167 168 168 // does not apply to web's flat navigator 169 - if (isNative && screen !== 'NotFound') { 169 + if (IS_NATIVE && screen !== 'NotFound') { 170 170 const state = navigation.getState() 171 171 // if screen is not in the current navigator, it means it's 172 172 // most likely a tab screen. note: state can be undefined ··· 251 251 (e: GestureResponderEvent) => { 252 252 const exitEarlyIfFalse = outerOnLongPress?.(e) 253 253 if (exitEarlyIfFalse === false) return 254 - return isNative && shareOnLongPress ? handleLongPress() : undefined 254 + return IS_NATIVE && shareOnLongPress ? handleLongPress() : undefined 255 255 }, 256 256 [outerOnLongPress, handleLongPress, shareOnLongPress], 257 257 ) ··· 506 506 onPress, 507 507 ...props 508 508 }: Omit<InlineLinkProps, 'onLongPress'>) { 509 - return isWeb ? ( 509 + return IS_WEB ? ( 510 510 <InlineLinkText {...props} to={to} onPress={onPress}> 511 511 {children} 512 512 </InlineLinkText> ··· 552 552 ): {onPress: Exclude<BaseLinkProps['onPress'], undefined>} { 553 553 return { 554 554 onPress(e: GestureResponderEvent) { 555 - if (!isWeb || !isModifiedClickEvent(e)) { 555 + if (!IS_WEB || !isModifiedClickEvent(e)) { 556 556 e.preventDefault() 557 557 onPressHandler(e) 558 558 return false ··· 566 566 * intends to deviate from default behavior. 567 567 */ 568 568 export function isClickEventWithMetaKey(e: GestureResponderEvent) { 569 - if (!isWeb) return false 569 + if (!IS_WEB) return false 570 570 const event = e as unknown as MouseEvent 571 571 return event.metaKey || event.altKey || event.ctrlKey || event.shiftKey 572 572 } ··· 575 575 * Determines if the web click target is anything other than `_self` 576 576 */ 577 577 export function isClickTargetExternal(e: GestureResponderEvent) { 578 - if (!isWeb) return false 578 + if (!IS_WEB) return false 579 579 const event = e as unknown as MouseEvent 580 580 const el = event.currentTarget as HTMLAnchorElement 581 581 return el && el.target && el.target !== '_self' ··· 587 587 * {@link https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button} 588 588 */ 589 589 export function isModifiedClickEvent(e: GestureResponderEvent): boolean { 590 - if (!isWeb) return false 590 + if (!IS_WEB) return false 591 591 const event = e as unknown as MouseEvent 592 592 const isPrimaryButton = event.button === 0 593 593 return ( ··· 601 601 * {@link https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button} 602 602 */ 603 603 export function shouldClickOpenNewTab(e: GestureResponderEvent) { 604 - if (!isWeb) return false 604 + if (!IS_WEB) return false 605 605 const event = e as unknown as MouseEvent 606 - const isMiddleClick = isWeb && event.button === 1 606 + const isMiddleClick = IS_WEB && event.button === 1 607 607 return isClickEventWithMetaKey(e) || isClickTargetExternal(e) || isMiddleClick 608 608 }
+2 -2
src/components/MediaInsetBorder.tsx
··· 1 1 import {StyleSheet} from 'react-native' 2 2 import type React from 'react' 3 3 4 - import {isHighDPI} from '#/lib/browser' 5 4 import {atoms as a, platform, useTheme, type ViewStyleProp} from '#/alf' 6 5 import {Fill} from '#/components/Fill' 6 + import {IS_HIGH_DPI} from '#/env' 7 7 8 8 /** 9 9 * Applies and thin border within a bounding box. Used to contrast media from ··· 33 33 // while we generally use hairlineWidth (aka 1px), 34 34 // we make an exception here for high DPI screens 35 35 // as the 1px border is very noticeable -sfn 36 - web: isHighDPI ? 0.5 : StyleSheet.hairlineWidth, 36 + web: IS_HIGH_DPI ? 0.5 : StyleSheet.hairlineWidth, 37 37 }), 38 38 }, 39 39 opaque
+5 -5
src/components/Menu/index.tsx
··· 10 10 import {useLingui} from '@lingui/react' 11 11 import flattenReactChildren from 'react-keyed-flatten-children' 12 12 13 - import {isAndroid, isIOS, isNative} from '#/platform/detection' 14 13 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 15 14 import {atoms as a, useTheme} from '#/alf' 16 15 import {Button, ButtonText} from '#/components/Button' ··· 31 30 type TriggerProps, 32 31 } from '#/components/Menu/types' 33 32 import {Text} from '#/components/Typography' 33 + import {IS_ANDROID, IS_IOS, IS_NATIVE} from '#/env' 34 34 35 35 export { 36 36 type DialogControlProps as MenuControlProps, ··· 71 71 } = useInteractionState() 72 72 73 73 return children({ 74 - isNative: true, 74 + IS_NATIVE: true, 75 75 control: context.control, 76 76 state: { 77 77 hovered: false, ··· 112 112 <Dialog.ScrollableInner label={_(msg`Menu`)}> 113 113 <View style={[a.gap_lg]}> 114 114 {children} 115 - {isNative && showCancel && <Cancel />} 115 + {IS_NATIVE && showCancel && <Cancel />} 116 116 </View> 117 117 </Dialog.ScrollableInner> 118 118 </Context.Provider> ··· 138 138 onFocus={onFocus} 139 139 onBlur={onBlur} 140 140 onPress={async e => { 141 - if (isAndroid) { 141 + if (IS_ANDROID) { 142 142 /** 143 143 * Below fix for iOS doesn't work for Android, this does. 144 144 */ 145 145 onPress?.(e) 146 146 context.control.close() 147 - } else if (isIOS) { 147 + } else if (IS_IOS) { 148 148 /** 149 149 * Fixes a subtle bug on iOS 150 150 * {@link https://github.com/bluesky-social/social-app/pull/5849/files#diff-de516ef5e7bd9840cd639213301df38cf03acfcad5bda85a1d63efd249ba79deL124-L127}
+1 -1
src/components/Menu/index.web.tsx
··· 139 139 <RadixTriggerPassThrough> 140 140 {props => 141 141 children({ 142 - isNative: false, 142 + IS_NATIVE: false, 143 143 control, 144 144 state: { 145 145 hovered,
+2 -2
src/components/Menu/types.ts
··· 43 43 } 44 44 export type TriggerChildProps = 45 45 | { 46 - isNative: true 46 + IS_NATIVE: true 47 47 control: Dialog.DialogOuterProps['control'] 48 48 state: { 49 49 /** ··· 73 73 } 74 74 } 75 75 | { 76 - isNative: false 76 + IS_NATIVE: false 77 77 control: Dialog.DialogOuterProps['control'] 78 78 state: { 79 79 hovered: boolean
+2 -2
src/components/NewskieDialog.tsx
··· 8 8 import {HITSLOP_10} from '#/lib/constants' 9 9 import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 10 10 import {sanitizeDisplayName} from '#/lib/strings/display-names' 11 - import {isNative} from '#/platform/detection' 12 11 import {useModerationOpts} from '#/state/preferences/moderation-opts' 13 12 import {useSession} from '#/state/session' 14 13 import {atoms as a, useTheme, web} from '#/alf' ··· 18 17 import {Newskie} from '#/components/icons/Newskie' 19 18 import * as StarterPackCard from '#/components/StarterPack/StarterPackCard' 20 19 import {Text} from '#/components/Typography' 20 + import {IS_NATIVE} from '#/env' 21 21 22 22 export function NewskieDialog({ 23 23 profile, ··· 162 162 </StarterPackCard.Link> 163 163 ) : null} 164 164 165 - {isNative && ( 165 + {IS_NATIVE && ( 166 166 <Button 167 167 label={_(msg`Close`)} 168 168 color="secondary"
+3 -3
src/components/PolicyUpdateOverlay/Overlay.tsx
··· 7 7 import {LinearGradient} from 'expo-linear-gradient' 8 8 import {utils} from '@bsky.app/alf' 9 9 10 - import {isAndroid, isNative} from '#/platform/detection' 11 10 import {useA11y} from '#/state/a11y' 12 11 import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' 13 12 import {FocusScope} from '#/components/FocusScope' 14 13 import {LockScroll} from '#/components/LockScroll' 14 + import {IS_ANDROID, IS_NATIVE} from '#/env' 15 15 16 16 const GUTTER = 24 17 17 ··· 80 80 a.z_20, 81 81 a.align_center, 82 82 !gtPhone && [a.justify_end, {minHeight: frame.height}], 83 - isNative && [ 83 + IS_NATIVE && [ 84 84 { 85 85 paddingBottom: Math.max(insets.bottom, a.p_2xl.padding), 86 86 }, ··· 109 109 110 110 <FocusScope> 111 111 <View 112 - accessible={isAndroid} 112 + accessible={IS_ANDROID} 113 113 role="dialog" 114 114 aria-role="dialog" 115 115 aria-label={label}
+2 -2
src/components/PolicyUpdateOverlay/index.tsx
··· 1 1 import {useEffect} from 'react' 2 2 import {View} from 'react-native' 3 3 4 - import {isIOS} from '#/platform/detection' 5 4 import {atoms as a} from '#/alf' 6 5 import {FullWindowOverlay} from '#/components/FullWindowOverlay' 7 6 import {usePolicyUpdateContext} from '#/components/PolicyUpdateOverlay/context' 8 7 import {Portal} from '#/components/PolicyUpdateOverlay/Portal' 9 8 import {Content} from '#/components/PolicyUpdateOverlay/updates/202508' 9 + import {IS_IOS} from '#/env' 10 10 11 11 export {Provider} from '#/components/PolicyUpdateOverlay/context' 12 12 export {usePolicyUpdateContext} from '#/components/PolicyUpdateOverlay/context' ··· 39 39 // setting a zIndex when using FullWindowOverlay on iOS 40 40 // means the taps pass straight through to the underlying content (???) 41 41 // so don't set it on iOS. FullWindowOverlay already does the job. 42 - !isIOS && {zIndex: 9999}, 42 + !IS_IOS && {zIndex: 9999}, 43 43 ]}> 44 44 <Content state={state} /> 45 45 </View>
+2 -2
src/components/PolicyUpdateOverlay/updates/202508/index.tsx
··· 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {isAndroid} from '#/platform/detection' 7 6 import {useA11y} from '#/state/a11y' 8 7 import {atoms as a, useTheme} from '#/alf' 9 8 import {Button, ButtonText} from '#/components/Button' ··· 12 11 import {Overlay} from '#/components/PolicyUpdateOverlay/Overlay' 13 12 import {type PolicyUpdateState} from '#/components/PolicyUpdateOverlay/usePolicyUpdateState' 14 13 import {Text} from '#/components/Typography' 14 + import {IS_ANDROID} from '#/env' 15 15 16 16 export function Content({state}: {state: PolicyUpdateState}) { 17 17 const t = useTheme() ··· 56 56 size: 'small', 57 57 } as const 58 58 59 - const label = isAndroid 59 + const label = IS_ANDROID 60 60 ? _( 61 61 msg`We’re updating our Terms of Service, Privacy Policy, and Copyright Policy, effective September 15th, 2025. We're also updating our Community Guidelines, and we want your input! These new guidelines will take effect on October 15th, 2025. Learn more about these changes and how to share your thoughts with us by reading our blog post.`, 62 62 )
+5 -5
src/components/Post/Embed/ExternalEmbed/ExternalGif.tsx
··· 10 10 import {useLingui} from '@lingui/react' 11 11 12 12 import {type EmbedPlayerParams} from '#/lib/strings/embed-player' 13 - import {isIOS, isNative, isWeb} from '#/platform/detection' 14 13 import {useExternalEmbedsPrefs} from '#/state/preferences' 15 14 import {atoms as a, useTheme} from '#/alf' 16 15 import {useDialogControl} from '#/components/Dialog' 17 16 import {EmbedConsentDialog} from '#/components/dialogs/EmbedConsent' 18 17 import {Fill} from '#/components/Fill' 19 18 import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' 19 + import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env' 20 20 21 21 export function ExternalGif({ 22 22 link, ··· 66 66 // Control animation on native 67 67 setIsAnimating(prev => { 68 68 if (prev) { 69 - if (isNative) { 69 + if (IS_NATIVE) { 70 70 imageRef.current?.stopAnimating() 71 71 } 72 72 return false 73 73 } else { 74 - if (isNative) { 74 + if (IS_NATIVE) { 75 75 imageRef.current?.startAnimating() 76 76 } 77 77 return true ··· 112 112 <Image 113 113 source={{ 114 114 uri: 115 - !isPrefetched || (isWeb && !isAnimating) 115 + !isPrefetched || (IS_WEB && !isAnimating) 116 116 ? link.thumb 117 117 : params.playerUri, 118 118 }} // Web uses the thumb to control playback ··· 123 123 accessibilityIgnoresInvertColors 124 124 accessibilityLabel={link.title} 125 125 accessibilityHint={link.title} 126 - cachePolicy={isIOS ? 'disk' : 'memory-disk'} // cant control playback with memory-disk on ios 126 + cachePolicy={IS_IOS ? 'disk' : 'memory-disk'} // cant control playback with memory-disk on ios 127 127 /> 128 128 129 129 {(!isPrefetched || !isAnimating) && (
+2 -2
src/components/Post/Embed/ExternalEmbed/ExternalPlayer.tsx
··· 26 26 type EmbedPlayerParams, 27 27 getPlayerAspect, 28 28 } from '#/lib/strings/embed-player' 29 - import {isNative} from '#/platform/detection' 30 29 import {useExternalEmbedsPrefs} from '#/state/preferences' 31 30 import {EventStopper} from '#/view/com/util/EventStopper' 32 31 import {atoms as a, useTheme} from '#/alf' ··· 34 33 import {EmbedConsentDialog} from '#/components/dialogs/EmbedConsent' 35 34 import {Fill} from '#/components/Fill' 36 35 import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' 36 + import {IS_NATIVE} from '#/env' 37 37 38 38 interface ShouldStartLoadRequest { 39 39 url: string ··· 148 148 const {height: winHeight, width: winWidth} = windowDims 149 149 150 150 // Get the proper screen height depending on what is going on 151 - const realWinHeight = isNative // If it is native, we always want the larger number 151 + const realWinHeight = IS_NATIVE // If it is native, we always want the larger number 152 152 ? winHeight > winWidth 153 153 ? winHeight 154 154 : winWidth
+6 -6
src/components/Post/Embed/ExternalEmbed/Gif.tsx
··· 13 13 import {HITSLOP_20} from '#/lib/constants' 14 14 import {clamp} from '#/lib/numbers' 15 15 import {type EmbedPlayerParams} from '#/lib/strings/embed-player' 16 - import {isWeb} from '#/platform/detection' 17 16 import {useAutoplayDisabled} from '#/state/preferences' 18 17 import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' 19 18 import {atoms as a, useTheme} from '#/alf' ··· 22 21 import * as Prompt from '#/components/Prompt' 23 22 import {Text} from '#/components/Typography' 24 23 import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' 24 + import {IS_WEB} from '#/env' 25 25 import {GifView} from '../../../../../modules/expo-bluesky-gif-view' 26 26 import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types' 27 27 ··· 218 218 altContainer: { 219 219 backgroundColor: 'rgba(0, 0, 0, 0.75)', 220 220 borderRadius: 6, 221 - paddingHorizontal: isWeb ? 8 : 6, 222 - paddingVertical: isWeb ? 6 : 3, 221 + paddingHorizontal: IS_WEB ? 8 : 6, 222 + paddingVertical: IS_WEB ? 6 : 3, 223 223 position: 'absolute', 224 224 // Related to margin/gap hack. This keeps the alt label in the same position 225 225 // on all platforms 226 - right: isWeb ? 8 : 5, 227 - bottom: isWeb ? 8 : 5, 226 + right: IS_WEB ? 8 : 5, 227 + bottom: IS_WEB ? 8 : 5, 228 228 zIndex: 2, 229 229 }, 230 230 alt: { 231 231 color: 'white', 232 - fontSize: isWeb ? 10 : 7, 232 + fontSize: IS_WEB ? 10 : 7, 233 233 fontWeight: '600', 234 234 }, 235 235 })
+2 -2
src/components/Post/Embed/ExternalEmbed/index.tsx
··· 10 10 import {shareUrl} from '#/lib/sharing' 11 11 import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player' 12 12 import {toNiceDomain} from '#/lib/strings/url-helpers' 13 - import {isNative} from '#/platform/detection' 14 13 import {useExternalEmbedsPrefs} from '#/state/preferences' 15 14 import {atoms as a, useTheme} from '#/alf' 16 15 import {Divider} from '#/components/Divider' 17 16 import {Earth_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe' 18 17 import {Link} from '#/components/Link' 19 18 import {Text} from '#/components/Typography' 19 + import {IS_NATIVE} from '#/env' 20 20 import {ExternalGif} from './ExternalGif' 21 21 import {ExternalPlayer} from './ExternalPlayer' 22 22 import {GifEmbed} from './Gif' ··· 53 53 }, [playHaptic, onOpen]) 54 54 55 55 const onShareExternal = useCallback(() => { 56 - if (link.uri && isNative) { 56 + if (link.uri && IS_NATIVE) { 57 57 playHaptic('Heavy') 58 58 shareUrl(link.uri) 59 59 }
+3 -3
src/components/Post/Embed/VideoEmbed/ActiveVideoWebContext.tsx
··· 8 8 } from 'react' 9 9 import {useWindowDimensions} from 'react-native' 10 10 11 - import {isNative, isWeb} from '#/platform/detection' 11 + import {IS_NATIVE, IS_WEB} from '#/env' 12 12 13 13 const Context = React.createContext<{ 14 14 activeViewId: string | null ··· 18 18 Context.displayName = 'ActiveVideoWebContext' 19 19 20 20 export function Provider({children}: {children: React.ReactNode}) { 21 - if (!isWeb) { 21 + if (!IS_WEB) { 22 22 throw new Error('ActiveVideoWebContext may only be used on web.') 23 23 } 24 24 ··· 47 47 48 48 const sendViewPosition = useCallback( 49 49 (viewId: string, y: number) => { 50 - if (isNative) return 50 + if (IS_NATIVE) return 51 51 52 52 if (viewId === activeViewIdRef.current) { 53 53 activeViewLocationRef.current = y
+3 -3
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/Scrubber.tsx
··· 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {isFirefox, isTouchDevice} from '#/lib/browser' 7 6 import {clamp} from '#/lib/numbers' 8 7 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 9 8 import {atoms as a, useTheme, web} from '#/alf' 10 9 import {useInteractionState} from '#/components/hooks/useInteractionState' 10 + import {IS_WEB_FIREFOX, IS_WEB_TOUCH_DEVICE} from '#/env' 11 11 import {formatTime} from './utils' 12 12 13 13 export function Scrubber({ ··· 102 102 // a pointerUp event is fired outside the element that captured the 103 103 // pointer. Firefox clicks on the element the mouse is over, so we have 104 104 // to make everything unclickable while seeking -sfn 105 - if (isFirefox && scrubberActive) { 105 + if (IS_WEB_FIREFOX && scrubberActive) { 106 106 document.body.classList.add('force-no-clicks') 107 107 108 108 return () => { ··· 153 153 <View 154 154 testID="scrubber" 155 155 style={[ 156 - {height: isTouchDevice ? 32 : 18, width: '100%'}, 156 + {height: IS_WEB_TOUCH_DEVICE ? 32 : 18, width: '100%'}, 157 157 a.flex_shrink_0, 158 158 a.px_xs, 159 159 ]}
+7 -8
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 import type Hls from 'hls.js' 6 6 7 - import {isTouchDevice} from '#/lib/browser' 8 7 import {clamp} from '#/lib/numbers' 9 - import {isIPhoneWeb} from '#/platform/detection' 10 8 import { 11 9 useAutoplayDisabled, 12 10 useSetSubtitlesEnabled, ··· 28 26 import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play' 29 27 import {Loader} from '#/components/Loader' 30 28 import {Text} from '#/components/Typography' 29 + import {IS_WEB_MOBILE_IOS, IS_WEB_TOUCH_DEVICE} from '#/env' 31 30 import {TimeIndicator} from '../TimeIndicator' 32 31 import {ControlButton} from './ControlButton' 33 32 import {Scrubber} from './Scrubber' ··· 215 214 216 215 const seekLeft = useCallback(() => { 217 216 if (!videoRef.current) return 218 - // eslint-disable-next-line @typescript-eslint/no-shadow 217 + 219 218 const currentTime = videoRef.current.currentTime 220 - // eslint-disable-next-line @typescript-eslint/no-shadow 219 + 221 220 const duration = videoRef.current.duration || 0 222 221 onSeek(clamp(currentTime - 5, 0, duration)) 223 222 }, [onSeek, videoRef]) 224 223 225 224 const seekRight = useCallback(() => { 226 225 if (!videoRef.current) return 227 - // eslint-disable-next-line @typescript-eslint/no-shadow 226 + 228 227 const currentTime = videoRef.current.currentTime 229 - // eslint-disable-next-line @typescript-eslint/no-shadow 228 + 230 229 const duration = videoRef.current.duration || 0 231 230 onSeek(clamp(currentTime + 5, 0, duration)) 232 231 }, [onSeek, videoRef]) ··· 342 341 {opacity: showControls ? 1 : 0}, 343 342 {transition: 'opacity 0.2s ease-in-out'}, 344 343 ]}> 345 - {(!volumeHovered || isTouchDevice) && ( 344 + {(!volumeHovered || IS_WEB_TOUCH_DEVICE) && ( 346 345 <Scrubber 347 346 duration={duration} 348 347 currentTime={currentTime} ··· 400 399 onEndHover={onVolumeEndHover} 401 400 drawFocus={drawFocus} 402 401 /> 403 - {!isIPhoneWeb && ( 402 + {!IS_WEB_MOBILE_IOS && ( 404 403 <ControlButton 405 404 active={isFullscreen} 406 405 activeLabel={_(msg`Exit fullscreen`)}
+5 -3
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx
··· 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {isSafari, isTouchDevice} from '#/lib/browser' 8 7 import {atoms as a} from '#/alf' 9 8 import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' 10 9 import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker' 11 10 import {useVideoVolumeState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' 11 + import {IS_WEB_SAFARI, IS_WEB_TOUCH_DEVICE} from '#/env' 12 12 import {ControlButton} from './ControlButton' 13 13 14 14 export function VolumeControl({ ··· 57 57 onPointerEnter={onHover} 58 58 onPointerLeave={onEndHover} 59 59 style={[a.relative]}> 60 - {hovered && !isTouchDevice && ( 60 + {hovered && !IS_WEB_TOUCH_DEVICE && ( 61 61 <Animated.View 62 62 entering={FadeIn.duration(100)} 63 63 exiting={FadeOut.duration(100)} ··· 80 80 aria-label={_(msg`Volume`)} 81 81 style={ 82 82 // Ridiculous safari hack for old version of safari. Fixed in sonoma beta -h 83 - isSafari ? {height: 92, minHeight: '100%'} : {height: '100%'} 83 + IS_WEB_SAFARI 84 + ? {height: 92, minHeight: '100%'} 85 + : {height: '100%'} 84 86 } 85 87 onChange={onVolumeChange} 86 88 // @ts-expect-error for old versions of firefox, and then re-using it for targeting the CSS -sfn
+2 -2
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/utils.tsx
··· 1 1 import {type RefObject, useCallback, useEffect, useRef, useState} from 'react' 2 2 3 - import {isSafari} from '#/lib/browser' 4 3 import {logger} from '#/logger' 5 4 import {useVideoVolumeState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' 5 + import {IS_WEB_SAFARI} from '#/env' 6 6 7 7 export function useVideoElement(ref: RefObject<HTMLVideoElement | null>) { 8 8 const [playing, setPlaying] = useState(false) ··· 41 41 setCurrentTime(round(ref.current.currentTime) || 0) 42 42 // HACK: Safari randomly fires `stalled` events when changing between segments 43 43 // let's just clear the buffering state if the video is still progressing -sfn 44 - if (isSafari) { 44 + if (IS_WEB_SAFARI) { 45 45 if (bufferingTimeout) clearTimeout(bufferingTimeout) 46 46 setBuffering(false) 47 47 }
+3 -3
src/components/Post/Embed/VideoEmbed/index.web.tsx
··· 11 11 import {msg} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 13 14 - import {isFirefox} from '#/lib/browser' 15 14 import {ErrorBoundary} from '#/view/com/util/ErrorBoundary' 16 15 import {atoms as a, useTheme} from '#/alf' 17 16 import {useIsWithinMessage} from '#/components/dms/MessageContext' ··· 23 22 VideoEmbedInnerWeb, 24 23 VideoNotFoundError, 25 24 } from '#/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerWeb' 25 + import {IS_WEB_FIREFOX} from '#/env' 26 26 import {useActiveVideoWeb} from './ActiveVideoWebContext' 27 27 import * as VideoFallback from './VideoEmbedInner/VideoFallback' 28 28 ··· 37 37 38 38 useEffect(() => { 39 39 if (!ref.current) return 40 - if (isFullscreen && !isFirefox) return 40 + if (isFullscreen && !IS_WEB_FIREFOX) return 41 41 const observer = new IntersectionObserver( 42 42 entries => { 43 43 const entry = entries[0] ··· 150 150 // observing a div of 100vh height 151 151 useEffect(() => { 152 152 if (!ref.current) return 153 - if (isFullscreen && !isFirefox) return 153 + if (isFullscreen && !IS_WEB_FIREFOX) return 154 154 const observer = new IntersectionObserver( 155 155 entries => { 156 156 const entry = entries[0]
+3 -4
src/components/PostControls/PostMenu/PostMenuItems.tsx
··· 41 41 import {restoreLinks} from '#/lib/strings/rich-text-manip' 42 42 import {toShareUrl} from '#/lib/strings/url-helpers' 43 43 import {logger} from '#/logger' 44 - import {isWeb} from '#/platform/detection' 45 44 import {type Shadow} from '#/state/cache/post-shadow' 46 45 import {useProfileShadow} from '#/state/cache/profile-shadow' 47 46 import {useFeedFeedbackContext} from '#/state/feed-feedback' ··· 102 101 useReportDialogControl, 103 102 } from '#/components/moderation/ReportDialog' 104 103 import * as Prompt from '#/components/Prompt' 105 - import {IS_INTERNAL} from '#/env' 104 + import {IS_INTERNAL, IS_WEB} from '#/env' 106 105 import * as bsky from '#/types/bsky' 107 106 108 107 let PostMenuItems = ({ ··· 611 610 Toast.show(_(msg({message: 'Downloading video...', context: 'toast'}))) 612 611 613 612 let success 614 - if (isWeb) success = await downloadVideoWeb({uri: uri}) 613 + if (IS_WEB) success = await downloadVideoWeb({uri: uri}) 615 614 else success = await saveVideoToMediaLibrary({uri: uri}) 616 615 617 616 if (success) Toast.show('Video downloaded', 'check') ··· 624 623 Toast.show(_(msg({message: 'Downloading GIF...', context: 'toast'}))) 625 624 626 625 let success 627 - if (isWeb) success = await downloadVideoWeb({uri: gifEmbed.external.uri}) 626 + if (IS_WEB) success = await downloadVideoWeb({uri: gifEmbed.external.uri}) 628 627 else success = await saveVideoToMediaLibrary({uri: gifEmbed.external.uri}) 629 628 630 629 if (success) Toast.show('GIF downloaded', 'check')
+2 -2
src/components/PostControls/ShareMenu/ShareMenuItems.tsx
··· 11 11 import {shareText, shareUrl} from '#/lib/sharing' 12 12 import {toShareUrl, toShareUrlBsky} from '#/lib/strings/url-helpers' 13 13 import {logger} from '#/logger' 14 - import {isIOS} from '#/platform/detection' 15 14 import {useProfileShadow} from '#/state/cache/profile-shadow' 16 15 import {useShowExternalShareButtons} from '#/state/preferences/external-share-buttons' 17 16 import {useSession} from '#/state/session' ··· 27 26 import {SquareArrowTopRight_Stroke2_Corner0_Rounded as ExternalIcon} from '#/components/icons/SquareArrowTopRight' 28 27 import * as Menu from '#/components/Menu' 29 28 import {useAgeAssurance} from '#/ageAssurance' 29 + import {IS_IOS} from '#/env' 30 30 import {useDevMode} from '#/storage/hooks/dev-mode' 31 31 import {RecentChats} from './RecentChats' 32 32 import {type ShareMenuItemsProps} from './ShareMenuItems.types' ··· 74 74 const onCopyLink = async () => { 75 75 logger.metric('share:press:copyLink', {}, {statsig: true}) 76 76 const url = toShareUrl(href) 77 - if (isIOS) { 77 + if (IS_IOS) { 78 78 // iOS only 79 79 await ExpoClipboard.setUrlAsync(url) 80 80 } else {
+2 -2
src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
··· 10 10 import {shareText, shareUrl} from '#/lib/sharing' 11 11 import {toShareUrl, toShareUrlBsky} from '#/lib/strings/url-helpers' 12 12 import {logger} from '#/logger' 13 - import {isWeb} from '#/platform/detection' 14 13 import {useProfileShadow} from '#/state/cache/profile-shadow' 15 14 import {useShowExternalShareButtons} from '#/state/preferences/external-share-buttons' 16 15 import {useSession} from '#/state/session' ··· 25 24 import {SquareArrowTopRight_Stroke2_Corner0_Rounded as ExternalIcon} from '#/components/icons/SquareArrowTopRight' 26 25 import * as Menu from '#/components/Menu' 27 26 import {useAgeAssurance} from '#/ageAssurance' 27 + import {IS_WEB} from '#/env' 28 28 import {useDevMode} from '#/storage/hooks/dev-mode' 29 29 import {type ShareMenuItemsProps} from './ShareMenuItems.types' 30 30 ··· 81 81 }) 82 82 } 83 83 84 - const canEmbed = isWeb && gtMobile && !hideInPWI 84 + const canEmbed = IS_WEB && gtMobile && !hideInPWI 85 85 86 86 const onShareATURI = () => { 87 87 shareText(postUri)
+2 -2
src/components/ProfileHoverCard/index.web.tsx
··· 11 11 import {useNavigation} from '@react-navigation/native' 12 12 13 13 import {useActorStatus} from '#/lib/actor-status' 14 - import {isTouchDevice} from '#/lib/browser' 15 14 import {getModerationCauseKey} from '#/lib/moderation' 16 15 import {makeProfileLink} from '#/lib/routes/links' 17 16 import {type NavigationProp} from '#/lib/routes/types' ··· 47 46 import {Text} from '#/components/Typography' 48 47 import {useSimpleVerificationState} from '#/components/verification' 49 48 import {VerificationCheck} from '#/components/verification/VerificationCheck' 49 + import {IS_WEB_TOUCH_DEVICE} from '#/env' 50 50 import {type ProfileHoverCardProps} from './types' 51 51 52 52 const floatingMiddlewares = [ ··· 74 74 } 75 75 } 76 76 77 - if (props.disable || isTouchDevice) { 77 + if (props.disable || IS_WEB_TOUCH_DEVICE) { 78 78 return props.children 79 79 } else { 80 80 return (
+5 -5
src/components/ProgressGuide/FollowDialog.tsx
··· 12 12 import {popularInterests, useInterestsDisplayNames} from '#/lib/interests' 13 13 import {logEvent} from '#/lib/statsig/statsig' 14 14 import {logger} from '#/logger' 15 - import {isWeb} from '#/platform/detection' 16 15 import {useModerationOpts} from '#/state/preferences/moderation-opts' 17 16 import {useActorSearch} from '#/state/queries/actor-search' 18 17 import {usePreferencesQuery} from '#/state/queries/preferences' ··· 37 36 import {boostInterests, InterestTabs} from '#/components/InterestTabs' 38 37 import * as ProfileCard from '#/components/ProfileCard' 39 38 import {Text} from '#/components/Typography' 39 + import {IS_WEB} from '#/env' 40 40 import type * as bsky from '#/types/bsky' 41 41 import {ProgressGuideTask} from './Task' 42 42 ··· 431 431 <Trans>Find people to follow</Trans> 432 432 </Text> 433 433 {guide && ( 434 - <View style={isWeb && {paddingRight: 36}}> 434 + <View style={IS_WEB && {paddingRight: 36}}> 435 435 <ProgressGuideTask 436 436 current={guide.numFollows + 1} 437 437 total={10 + 1} ··· 440 440 /> 441 441 </View> 442 442 )} 443 - {isWeb ? ( 443 + {IS_WEB ? ( 444 444 <Button 445 445 label={_(msg`Close`)} 446 446 size="small" 447 447 shape="round" 448 - variant={isWeb ? 'ghost' : 'solid'} 448 + variant={IS_WEB ? 'ghost' : 'solid'} 449 449 color="secondary" 450 450 style={[ 451 451 a.absolute, ··· 579 579 <ProfileCard.Outer> 580 580 <ProfileCard.Header> 581 581 <ProfileCard.Avatar 582 - disabledPreview={!isWeb} 582 + disabledPreview={!IS_WEB} 583 583 profile={profile} 584 584 moderationOpts={moderationOpts} 585 585 />
+3 -3
src/components/ProgressGuide/Toast.tsx
··· 11 11 import {msg} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 13 14 - import {isWeb} from '#/platform/detection' 15 14 import {atoms as a, useTheme} from '#/alf' 16 15 import {Portal} from '#/components/Portal' 16 + import {IS_WEB} from '#/env' 17 17 import {AnimatedCheck, type AnimatedCheckRef} from '../anim/AnimatedCheck' 18 18 import {Text} from '../Typography' 19 19 ··· 108 108 const containerStyle = React.useMemo(() => { 109 109 let left = 10 110 110 let right = 10 111 - if (isWeb && winDim.width > 400) { 111 + if (IS_WEB && winDim.width > 400) { 112 112 left = right = (winDim.width - 380) / 2 113 113 } 114 114 return { 115 - position: isWeb ? 'fixed' : 'absolute', 115 + position: IS_WEB ? 'fixed' : 'absolute', 116 116 top: 0, 117 117 left, 118 118 right,
+5 -5
src/components/RichTextTag.tsx
··· 6 6 7 7 import {type NavigationProp} from '#/lib/routes/types' 8 8 import {isInvalidHandle} from '#/lib/strings/handles' 9 - import {isNative, isWeb} from '#/platform/detection' 10 9 import { 11 10 usePreferencesQuery, 12 11 useRemoveMutedWordsMutation, ··· 22 21 } from '#/components/Link' 23 22 import {Loader} from '#/components/Loader' 24 23 import * as Menu from '#/components/Menu' 24 + import {IS_NATIVE, IS_WEB} from '#/env' 25 25 26 26 export function RichTextTag({ 27 27 tag, ··· 50 50 const navigation = useNavigation<NavigationProp>() 51 51 const isCashtag = tag.startsWith('$') 52 52 const label = isCashtag ? _(msg`Cashtag ${tag}`) : _(msg`Hashtag ${tag}`) 53 - const hint = isNative 53 + const hint = IS_NATIVE 54 54 ? _(msg`Long press to open tag menu for ${isCashtag ? tag : `#${tag}`}`) 55 55 : _(msg`Click to open tag menu for ${isCashtag ? tag : `#${tag}`}`) 56 56 ··· 86 86 }} 87 87 {...menuProps} 88 88 onPress={e => { 89 - if (isWeb) { 89 + if (IS_WEB) { 90 90 return createStaticClickIfUnmodified(() => { 91 - if (!isNative) { 91 + if (!IS_NATIVE) { 92 92 menuProps.onPress() 93 93 } 94 94 }).onPress(e) ··· 99 99 label={label} 100 100 style={textStyle} 101 101 emoji> 102 - {isNative ? ( 102 + {IS_NATIVE ? ( 103 103 display 104 104 ) : ( 105 105 <RNText ref={menuProps.ref}>{display}</RNText>
+3 -3
src/components/ScreenTransition.tsx
··· 8 8 } from 'react-native-reanimated' 9 9 import type React from 'react' 10 10 11 - import {isWeb} from '#/platform/detection' 11 + import {IS_WEB} from '#/env' 12 12 13 13 export function ScreenTransition({ 14 14 direction, ··· 31 31 32 32 return ( 33 33 <Animated.View 34 - entering={isWeb ? webEntering : entering} 35 - exiting={isWeb ? webExiting : exiting} 34 + entering={IS_WEB ? webEntering : entering} 35 + exiting={IS_WEB ? webExiting : exiting} 36 36 style={style}> 37 37 {children} 38 38 </Animated.View>
+1 -1
src/components/Select/index.tsx
··· 82 82 83 83 if (typeof children === 'function') { 84 84 return children({ 85 - isNative: true, 85 + IS_NATIVE: true, 86 86 control, 87 87 state: { 88 88 hovered: false,
+1 -1
src/components/Select/index.web.tsx
··· 68 68 <RadixTriggerPassThrough> 69 69 {props => 70 70 children({ 71 - isNative: false, 71 + IS_NATIVE: false, 72 72 state: { 73 73 hovered, 74 74 focused,
+2 -2
src/components/Select/types.ts
··· 65 65 66 66 export type TriggerChildProps = 67 67 | { 68 - isNative: true 68 + IS_NATIVE: true 69 69 control: DialogControlProps 70 70 state: { 71 71 /** ··· 92 92 } 93 93 } 94 94 | { 95 - isNative: false 95 + IS_NATIVE: false 96 96 state: { 97 97 hovered: boolean 98 98 focused: boolean
+3 -3
src/components/StarterPack/Main/FeedsList.tsx
··· 3 3 import {type AppBskyFeedDefs} from '@atproto/api' 4 4 5 5 import {useBottomBarOffset} from '#/lib/hooks/useBottomBarOffset' 6 - import {isNative, isWeb} from '#/platform/detection' 7 6 import {List, type ListRef} from '#/view/com/util/List' 8 7 import {type SectionRef} from '#/screens/Profile/Sections/types' 9 8 import {atoms as a, useTheme} from '#/alf' 10 9 import * as FeedCard from '#/components/FeedCard' 10 + import {IS_NATIVE, IS_WEB} from '#/env' 11 11 12 12 function keyExtractor(item: AppBskyFeedDefs.GeneratorView) { 13 13 return item.uri ··· 27 27 28 28 const onScrollToTop = useCallback(() => { 29 29 scrollElRef.current?.scrollToOffset({ 30 - animated: isNative, 30 + animated: IS_NATIVE, 31 31 offset: -headerHeight, 32 32 }) 33 33 }, [scrollElRef, headerHeight]) ··· 44 44 <View 45 45 style={[ 46 46 a.p_lg, 47 - (isWeb || index !== 0) && a.border_t, 47 + (IS_WEB || index !== 0) && a.border_t, 48 48 t.atoms.border_contrast_low, 49 49 ]}> 50 50 <FeedCard.Default view={item} />
+2 -2
src/components/StarterPack/Main/PostsList.tsx
··· 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {isNative} from '#/platform/detection' 7 6 import {type FeedDescriptor} from '#/state/queries/post-feed' 8 7 import {PostFeed} from '#/view/com/posts/PostFeed' 9 8 import {EmptyState} from '#/view/com/util/EmptyState' 10 9 import {type ListRef} from '#/view/com/util/List' 11 10 import {type SectionRef} from '#/screens/Profile/Sections/types' 12 11 import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 12 + import {IS_NATIVE} from '#/env' 13 13 14 14 interface ProfilesListProps { 15 15 listUri: string ··· 24 24 25 25 const onScrollToTop = useCallback(() => { 26 26 scrollElRef.current?.scrollToOffset({ 27 - animated: isNative, 27 + animated: IS_NATIVE, 28 28 offset: -headerHeight, 29 29 }) 30 30 }, [scrollElRef, headerHeight])
+3 -3
src/components/StarterPack/Main/ProfilesList.tsx
··· 14 14 import {useBottomBarOffset} from '#/lib/hooks/useBottomBarOffset' 15 15 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 16 16 import {isBlockedOrBlocking} from '#/lib/moderation/blocked-and-muted' 17 - import {isNative, isWeb} from '#/platform/detection' 18 17 import {useAllListMembersQuery} from '#/state/queries/list-members' 19 18 import {useSession} from '#/state/session' 20 19 import {List, type ListRef} from '#/view/com/util/List' ··· 22 21 import {atoms as a, useTheme} from '#/alf' 23 22 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 24 23 import {Default as ProfileCard} from '#/components/ProfileCard' 24 + import {IS_NATIVE, IS_WEB} from '#/env' 25 25 26 26 function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic, index: number) { 27 27 return `${item.did}-${index}` ··· 75 75 } 76 76 const onScrollToTop = useCallback(() => { 77 77 scrollElRef.current?.scrollToOffset({ 78 - animated: isNative, 78 + animated: IS_NATIVE, 79 79 offset: -headerHeight, 80 80 }) 81 81 }, [scrollElRef, headerHeight]) ··· 93 93 style={[ 94 94 a.p_lg, 95 95 t.atoms.border_contrast_low, 96 - (isWeb || index !== 0) && a.border_t, 96 + (IS_WEB || index !== 0) && a.border_t, 97 97 ]}> 98 98 <ProfileCard 99 99 profile={item}
+2 -2
src/components/StarterPack/ProfileStarterPacks.tsx
··· 19 19 import {type NavigationProp} from '#/lib/routes/types' 20 20 import {parseStarterPackUri} from '#/lib/strings/starter-pack' 21 21 import {logger} from '#/logger' 22 - import {isIOS} from '#/platform/detection' 23 22 import {useActorStarterPacksQuery} from '#/state/queries/actor-starter-packs' 24 23 import { 25 24 EmptyState, ··· 36 35 import * as Prompt from '#/components/Prompt' 37 36 import {Default as StarterPackCard} from '#/components/StarterPack/StarterPackCard' 38 37 import {Text} from '#/components/Typography' 38 + import {IS_IOS} from '#/env' 39 39 40 40 interface SectionRef { 41 41 scrollToTop: () => void ··· 136 136 }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) 137 137 138 138 useEffect(() => { 139 - if (isIOS && enabled && scrollElRef.current) { 139 + if (IS_IOS && enabled && scrollElRef.current) { 140 140 const nativeTag = findNodeHandle(scrollElRef.current) 141 141 setScrollViewTag(nativeTag) 142 142 }
+6 -6
src/components/StarterPack/QrCode.tsx
··· 6 6 import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' 7 7 import {Trans} from '@lingui/macro' 8 8 9 - import {isWeb} from '#/platform/detection' 10 9 import {Logo} from '#/view/icons/Logo' 11 10 import {Logotype} from '#/view/icons/Logotype' 12 11 import {useTheme} from '#/alf' 13 12 import {atoms as a} from '#/alf' 14 13 import {LinearGradientBackground} from '#/components/LinearGradientBackground' 15 14 import {Text} from '#/components/Typography' 15 + import {IS_WEB} from '#/env' 16 16 import * as bsky from '#/types/bsky' 17 17 18 18 const LazyViewShot = lazy( ··· 121 121 return ( 122 122 <View style={{position: 'relative'}}> 123 123 {/* An SVG version of the logo is placed on top of normal `QRCode` `logo` prop, since the PNG fails to load before the export completes on web. */} 124 - {isWeb && logoArea && ( 124 + {IS_WEB && logoArea && ( 125 125 <View 126 126 style={{ 127 127 position: 'absolute', ··· 139 139 a.rounded_sm, 140 140 {height: 225, width: 225, backgroundColor: '#f3f3f3'}, 141 141 ]} 142 - pieceSize={isWeb ? 8 : 6} 142 + pieceSize={IS_WEB ? 8 : 6} 143 143 padding={20} 144 - pieceBorderRadius={isWeb ? 4.5 : 3.5} 144 + pieceBorderRadius={IS_WEB ? 4.5 : 3.5} 145 145 outerEyesOptions={{ 146 146 topLeft: { 147 147 borderRadius: [12, 12, 0, 12], ··· 159 159 innerEyesOptions={{borderRadius: 3}} 160 160 logo={{ 161 161 href: require('../../../assets/logo.png'), 162 - ...(isWeb && { 162 + ...(IS_WEB && { 163 163 onChange: onLogoAreaChange, 164 164 padding: 28, 165 165 }), 166 - ...(!isWeb && { 166 + ...(!IS_WEB && { 167 167 padding: 2, 168 168 scale: 0.95, 169 169 }),
+6 -6
src/components/StarterPack/QrCodeDialog.tsx
··· 9 9 import {useLingui} from '@lingui/react' 10 10 11 11 import {logger} from '#/logger' 12 - import {isNative, isWeb} from '#/platform/detection' 13 12 import {atoms as a, useBreakpoints} from '#/alf' 14 13 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15 14 import * as Dialog from '#/components/Dialog' ··· 20 19 import {Loader} from '#/components/Loader' 21 20 import {QrCode} from '#/components/StarterPack/QrCode' 22 21 import * as Toast from '#/components/Toast' 22 + import {IS_NATIVE, IS_WEB} from '#/env' 23 23 import * as bsky from '#/types/bsky' 24 24 25 25 export function QrCodeDialog({ ··· 56 56 57 57 const onSavePress = async () => { 58 58 ref.current?.capture?.().then(async (uri: string) => { 59 - if (isNative) { 59 + if (IS_NATIVE) { 60 60 const res = await requestMediaLibraryPermissionsAsync() 61 61 62 62 if (!res.granted) { ··· 111 111 }) 112 112 setIsSaveProcessing(false) 113 113 Toast.show( 114 - isWeb 114 + IS_WEB 115 115 ? _(msg`QR code has been downloaded!`) 116 116 : _(msg`QR code saved to your camera roll!`), 117 117 ) ··· 178 178 label={_(msg`Copy QR code`)} 179 179 color="primary_subtle" 180 180 size="large" 181 - onPress={isWeb ? onCopyPress : onSharePress}> 181 + onPress={IS_WEB ? onCopyPress : onSharePress}> 182 182 <ButtonIcon 183 183 icon={ 184 184 isCopyProcessing 185 185 ? Loader 186 - : isWeb 186 + : IS_WEB 187 187 ? ChainLinkIcon 188 188 : ShareIcon 189 189 } 190 190 /> 191 191 <ButtonText> 192 - {isWeb ? <Trans>Copy</Trans> : <Trans>Share</Trans>} 192 + {IS_WEB ? <Trans>Copy</Trans> : <Trans>Share</Trans>} 193 193 </ButtonText> 194 194 </Button> 195 195 <Button
+8 -4
src/components/StarterPack/ShareDialog.tsx
··· 8 8 import {shareUrl} from '#/lib/sharing' 9 9 import {getStarterPackOgCard} from '#/lib/strings/starter-pack' 10 10 import {logger} from '#/logger' 11 - import {isNative, isWeb} from '#/platform/detection' 12 11 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 13 12 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 14 13 import {type DialogControlProps} from '#/components/Dialog' ··· 18 17 import {QrCode_Stroke2_Corner0_Rounded as QrCodeIcon} from '#/components/icons/QrCode' 19 18 import {Loader} from '#/components/Loader' 20 19 import {Text} from '#/components/Typography' 20 + import {IS_NATIVE, IS_WEB} from '#/env' 21 21 22 22 interface Props { 23 23 starterPack: AppBskyGraphDefs.StarterPackView ··· 110 110 ], 111 111 ]}> 112 112 <Button 113 - label={isWeb ? _(msg`Copy link`) : _(msg`Share link`)} 113 + label={IS_WEB ? _(msg`Copy link`) : _(msg`Share link`)} 114 114 color="primary_subtle" 115 115 size="large" 116 116 onPress={onShareLink}> 117 117 <ButtonIcon icon={ChainLinkIcon} /> 118 118 <ButtonText> 119 - {isWeb ? <Trans>Copy Link</Trans> : <Trans>Share link</Trans>} 119 + {IS_WEB ? ( 120 + <Trans>Copy Link</Trans> 121 + ) : ( 122 + <Trans>Share link</Trans> 123 + )} 120 124 </ButtonText> 121 125 </Button> 122 126 <Button ··· 133 137 <Trans>Share QR code</Trans> 134 138 </ButtonText> 135 139 </Button> 136 - {isNative && ( 140 + {IS_NATIVE && ( 137 141 <Button 138 142 label={_(msg`Save image`)} 139 143 color="secondary"
+3 -3
src/components/StarterPack/Wizard/WizardEditListDialog.tsx
··· 10 10 import {useLingui} from '@lingui/react' 11 11 12 12 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 13 - import {isWeb} from '#/platform/detection' 14 13 import {type ListMethods} from '#/view/com/util/List' 15 14 import { 16 15 type WizardAction, ··· 24 23 WizardProfileCard, 25 24 } from '#/components/StarterPack/Wizard/WizardListCard' 26 25 import {Text} from '#/components/Typography' 26 + import {IS_WEB} from '#/env' 27 27 28 28 function keyExtractor( 29 29 item: AppBskyActorDefs.ProfileViewBasic | AppBskyFeedDefs.GeneratorView, ··· 95 95 a.mb_sm, 96 96 t.atoms.bg, 97 97 t.atoms.border_contrast_medium, 98 - isWeb 98 + IS_WEB 99 99 ? [ 100 100 a.align_center, 101 101 { ··· 113 113 )} 114 114 </Text> 115 115 <View style={{width: 60}}> 116 - {isWeb && ( 116 + {IS_WEB && ( 117 117 <Button 118 118 label={_(msg`Close`)} 119 119 variant="ghost"
+4 -5
src/components/SubtleHover.tsx
··· 1 1 import {View} from 'react-native' 2 2 3 - import {isTouchDevice} from '#/lib/browser' 4 - import {isNative, isWeb} from '#/platform/detection' 5 3 import {atoms as a, useTheme, type ViewStyleProp} from '#/alf' 4 + import {IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env' 6 5 7 6 export function SubtleHover({ 8 7 style, ··· 39 38 /> 40 39 ) 41 40 42 - if (isWeb && web) { 43 - return isTouchDevice ? null : el 44 - } else if (isNative && native) { 41 + if (IS_WEB && web) { 42 + return IS_WEB_TOUCH_DEVICE ? null : el 43 + } else if (IS_NATIVE && native) { 45 44 return el 46 45 } 47 46
+1
src/components/Typography.tsx
··· 35 35 if (__DEV__) { 36 36 if (!emoji && childHasEmoji(children)) { 37 37 logger.warn( 38 + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string 38 39 `Text: emoji detected but emoji not enabled: "${children}"\n\nPlease add <Text emoji />'`, 39 40 ) 40 41 }
+3 -3
src/components/WhoCanReply.tsx
··· 18 18 import {HITSLOP_10} from '#/lib/constants' 19 19 import {makeListLink, makeProfileLink} from '#/lib/routes/links' 20 20 import {logger} from '#/logger' 21 - import {isNative} from '#/platform/detection' 22 21 import { 23 22 type ThreadgateAllowUISetting, 24 23 threadgateViewToAllowUISetting, ··· 37 36 import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group' 38 37 import {InlineLinkText} from '#/components/Link' 39 38 import {Text} from '#/components/Typography' 39 + import {IS_NATIVE} from '#/env' 40 40 import * as bsky from '#/types/bsky' 41 41 42 42 interface WhoCanReplyProps { ··· 86 86 : _(msg`Some people can reply`) 87 87 88 88 const onPressOpen = () => { 89 - if (isNative && Keyboard.isVisible()) { 89 + if (IS_NATIVE && Keyboard.isVisible()) { 90 90 Keyboard.dismiss() 91 91 } 92 92 if (isThreadAuthor) { ··· 229 229 embeddingDisabled={embeddingDisabled} 230 230 /> 231 231 </View> 232 - {isNative && ( 232 + {IS_NATIVE && ( 233 233 <Button 234 234 label={_(msg`Close`)} 235 235 onPress={() => control.close()}
+2 -2
src/components/activity-notifications/SubscribeProfileDialog.tsx
··· 18 18 import {cleanError} from '#/lib/strings/errors' 19 19 import {sanitizeHandle} from '#/lib/strings/handles' 20 20 import {logger} from '#/logger' 21 - import {isWeb} from '#/platform/detection' 22 21 import {updateProfileShadow} from '#/state/cache/profile-shadow' 23 22 import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions' 24 23 import {useAgent} from '#/state/session' ··· 37 36 import {Loader} from '#/components/Loader' 38 37 import * as ProfileCard from '#/components/ProfileCard' 39 38 import {Text} from '#/components/Typography' 39 + import {IS_WEB} from '#/env' 40 40 import type * as bsky from '#/types/bsky' 41 41 42 42 export function SubscribeProfileDialog({ ··· 195 195 } 196 196 } else { 197 197 // on web, a disabled save button feels more natural than a massive close button 198 - if (isWeb) { 198 + if (IS_WEB) { 199 199 return { 200 200 label: _(msg`Save changes`), 201 201 color: 'secondary',
+2 -2
src/components/ageAssurance/AgeAssuranceAccountCard.tsx
··· 3 3 import {useLingui} from '@lingui/react' 4 4 5 5 import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 6 - import {isNative} from '#/platform/detection' 7 6 import {atoms as a, useBreakpoints, useTheme, type ViewStyleProp} from '#/alf' 8 7 import {Admonition} from '#/components/Admonition' 9 8 import {AgeAssuranceAppealDialog} from '#/components/ageAssurance/AgeAssuranceAppealDialog' ··· 23 22 import {Text} from '#/components/Typography' 24 23 import {logger, useAgeAssurance} from '#/ageAssurance' 25 24 import {useComputeAgeAssuranceRegionAccess} from '#/ageAssurance/useComputeAgeAssuranceRegionAccess' 25 + import {IS_NATIVE} from '#/env' 26 26 import {useDeviceGeolocationApi} from '#/geolocation' 27 27 28 28 export function AgeAssuranceAccountCard({style}: ViewStyleProp & {}) { ··· 86 86 <View style={[a.pb_md, a.gap_xs]}> 87 87 <Text style={[a.text_sm, a.leading_snug]}>{copy.notice}</Text> 88 88 89 - {isNative && ( 89 + {IS_NATIVE && ( 90 90 <> 91 91 <Text style={[a.text_sm, a.leading_snug]}> 92 92 <Trans>
+3 -3
src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx
··· 5 5 6 6 import {retry} from '#/lib/async/retry' 7 7 import {wait} from '#/lib/async/wait' 8 - import {isNative} from '#/platform/detection' 9 8 import {useAgent} from '#/state/session' 10 9 import {atoms as a, useTheme, web} from '#/alf' 11 10 import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' ··· 18 17 import {Text} from '#/components/Typography' 19 18 import {refetchAgeAssuranceServerState} from '#/ageAssurance' 20 19 import {logger} from '#/ageAssurance' 20 + import {IS_NATIVE} from '#/env' 21 21 22 22 export type AgeAssuranceRedirectDialogState = { 23 23 result: 'success' | 'unknown' ··· 166 166 </Trans> 167 167 </Text> 168 168 169 - {isNative && ( 169 + {IS_NATIVE && ( 170 170 <View style={[a.w_full, a.pt_lg]}> 171 171 <Button 172 172 label={_(msg`Close`)} ··· 225 225 )} 226 226 </Text> 227 227 228 - {error && isNative && ( 228 + {error && IS_NATIVE && ( 229 229 <View style={[a.w_full, a.pt_lg]}> 230 230 <Button 231 231 label={_(msg`Close`)}
+2 -2
src/components/contacts/FindContactsBannerNUX.tsx
··· 8 8 import {HITSLOP_10} from '#/lib/constants' 9 9 import {useGate} from '#/lib/statsig/statsig' 10 10 import {logger} from '#/logger' 11 - import {isWeb} from '#/platform/detection' 12 11 import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs' 13 12 import {atoms as a, useTheme} from '#/alf' 14 13 import {Button} from '#/components/Button' 15 14 import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' 16 15 import {Text} from '#/components/Typography' 16 + import {IS_WEB} from '#/env' 17 17 import {Link} from '../Link' 18 18 import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allowlist' 19 19 ··· 92 92 const gate = useGate() 93 93 94 94 const visible = useMemo(() => { 95 - if (isWeb) return false 95 + if (IS_WEB) return false 96 96 if (hidden) return false 97 97 if (nux && nux.completed) return false 98 98 if (!isFeatureEnabled) return false
+3 -3
src/components/contacts/components/OTPInput.tsx
··· 9 9 import {useLingui} from '@lingui/react' 10 10 11 11 import {mergeRefs} from '#/lib/merge-refs' 12 - import {isAndroid, isIOS} from '#/platform/detection' 13 12 import {atoms as a, ios, platform, useTheme} from '#/alf' 14 13 import {useInteractionState} from '#/components/hooks/useInteractionState' 15 14 import {Text} from '#/components/Typography' 15 + import {IS_ANDROID, IS_IOS} from '#/env' 16 16 17 17 export function OTPInput({ 18 18 label, ··· 95 95 <TextInput 96 96 // SMS autofill is borked on iOS if you open the keyboard immediately -sfn 97 97 onLayout={ios(() => setTimeout(() => innerRef.current?.focus(), 100))} 98 - autoFocus={isAndroid} 98 + autoFocus={IS_ANDROID} 99 99 accessible 100 100 accessibilityLabel={label} 101 101 accessibilityHint="" ··· 135 135 android: {opacity: 0}, 136 136 }), 137 137 ]} 138 - caretHidden={isIOS} 138 + caretHidden={IS_IOS} 139 139 clearTextOnFocus 140 140 /> 141 141 </Pressable>
+3 -3
src/components/dialogs/BirthDateSettings.tsx
··· 7 7 import {isAppPassword} from '#/lib/jwt' 8 8 import {getAge, getDateAgo} from '#/lib/strings/time' 9 9 import {logger} from '#/logger' 10 - import {isIOS, isWeb} from '#/platform/detection' 11 10 import { 12 11 useBirthdateMutation, 13 12 useIsBirthdateUpdateAllowed, ··· 26 25 import {SimpleInlineLinkText} from '#/components/Link' 27 26 import {Loader} from '#/components/Loader' 28 27 import {Span, Text} from '#/components/Typography' 28 + import {IS_IOS, IS_WEB} from '#/env' 29 29 30 30 export function BirthDateSettingsDialog({ 31 31 control, ··· 154 154 155 155 return ( 156 156 <View style={a.gap_lg} testID="birthDateSettingsDialog"> 157 - <View style={isIOS && [a.w_full, a.align_center]}> 157 + <View style={IS_IOS && [a.w_full, a.align_center]}> 158 158 <DateField 159 159 testID="birthdayInput" 160 160 value={date} ··· 191 191 <ErrorMessage message={errorMessage} style={[a.rounded_sm]} /> 192 192 ) : undefined} 193 193 194 - <View style={isWeb && [a.flex_row, a.justify_end]}> 194 + <View style={IS_WEB && [a.flex_row, a.justify_end]}> 195 195 <Button 196 196 label={hasChanged ? _(msg`Save birthdate`) : _(msg`Done`)} 197 197 size="large"
+4 -4
src/components/dialogs/DeviceLocationRequestDialog.tsx
··· 6 6 import {wait} from '#/lib/async/wait' 7 7 import {isNetworkError, useCleanError} from '#/lib/hooks/useCleanError' 8 8 import {logger} from '#/logger' 9 - import {isWeb} from '#/platform/detection' 10 9 import {atoms as a, useTheme, web} from '#/alf' 11 10 import {Admonition} from '#/components/Admonition' 12 11 import {Button, ButtonIcon, ButtonText} from '#/components/Button' ··· 14 13 import {PinLocation_Stroke2_Corner0_Rounded as LocationIcon} from '#/components/icons/PinLocation' 15 14 import {Loader} from '#/components/Loader' 16 15 import {Text} from '#/components/Typography' 16 + import {IS_WEB} from '#/env' 17 17 import {type Geolocation, useRequestDeviceGeolocation} from '#/geolocation' 18 18 19 19 export type Props = { ··· 138 138 disabled={isRequesting} 139 139 label={_(msg`Allow location access`)} 140 140 onPress={onPressConfirm} 141 - size={isWeb ? 'small' : 'large'} 141 + size={IS_WEB ? 'small' : 'large'} 142 142 color="primary"> 143 143 <ButtonIcon icon={isRequesting ? Loader : LocationIcon} /> 144 144 <ButtonText> ··· 147 147 </Button> 148 148 )} 149 149 150 - {!isWeb && ( 150 + {!IS_WEB && ( 151 151 <Button 152 152 label={_(msg`Cancel`)} 153 153 onPress={() => close()} 154 - size={isWeb ? 'small' : 'large'} 154 + size={IS_WEB ? 'small' : 'large'} 155 155 color="secondary"> 156 156 <ButtonText> 157 157 <Trans>Cancel</Trans>
+3 -3
src/components/dialogs/GifSelect.tsx
··· 13 13 14 14 import {logEvent} from '#/lib/statsig/statsig' 15 15 import {cleanError} from '#/lib/strings/errors' 16 - import {isWeb} from '#/platform/detection' 17 16 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 18 17 import { 19 18 type Gif, ··· 32 31 import {ArrowLeft_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow' 33 32 import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass' 34 33 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 34 + import {IS_WEB} from '#/env' 35 35 36 36 export function GifSelectDialog({ 37 37 controlRef, ··· 152 152 a.pb_sm, 153 153 t.atoms.bg, 154 154 ]}> 155 - {!gtMobile && isWeb && ( 155 + {!gtMobile && IS_WEB && ( 156 156 <Button 157 157 size="small" 158 158 variant="ghost" ··· 164 164 </Button> 165 165 )} 166 166 167 - <TextField.Root style={[!gtMobile && isWeb && a.flex_1]}> 167 + <TextField.Root style={[!gtMobile && IS_WEB && a.flex_1]}> 168 168 <TextField.Icon icon={Search} /> 169 169 <TextField.Input 170 170 label={_(msg`Search GIFs`)}
+2 -2
src/components/dialogs/InAppBrowserConsent.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {useOpenLink} from '#/lib/hooks/useOpenLink' 7 - import {isWeb} from '#/platform/detection' 8 7 import {useSetInAppBrowser} from '#/state/preferences/in-app-browser' 9 8 import {atoms as a, useTheme} from '#/alf' 10 9 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 11 10 import * as Dialog from '#/components/Dialog' 12 11 import {SquareArrowTopRight_Stroke2_Corner0_Rounded as External} from '#/components/icons/SquareArrowTopRight' 13 12 import {Text} from '#/components/Typography' 13 + import {IS_WEB} from '#/env' 14 14 import {useGlobalDialogsControlContext} from './Context' 15 15 16 16 export function InAppBrowserConsentDialog() { 17 17 const {inAppBrowserConsentControl} = useGlobalDialogsControlContext() 18 18 19 - if (isWeb) return null 19 + if (IS_WEB) return null 20 20 21 21 return ( 22 22 <Dialog.Outer
+2 -2
src/components/dialogs/MutedWords.tsx
··· 5 5 import {useLingui} from '@lingui/react' 6 6 7 7 import {logger} from '#/logger' 8 - import {isNative} from '#/platform/detection' 9 8 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 10 9 import { 11 10 usePreferencesQuery, ··· 33 32 import {Loader} from '#/components/Loader' 34 33 import * as Prompt from '#/components/Prompt' 35 34 import {Text} from '#/components/Typography' 35 + import {IS_NATIVE} from '#/env' 36 36 37 37 const ONE_DAY = 24 * 60 * 60 * 1000 38 38 ··· 407 407 )} 408 408 </View> 409 409 410 - {isNative && <View style={{height: 20}} />} 410 + {IS_NATIVE && <View style={{height: 20}} />} 411 411 </View> 412 412 413 413 <Dialog.Close />
+2 -2
src/components/dialogs/PostInteractionSettingsDialog.tsx
··· 12 12 import {useHaptics} from '#/lib/haptics' 13 13 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 14 14 import {logger} from '#/logger' 15 - import {isIOS} from '#/platform/detection' 16 15 import {STALE} from '#/state/queries' 17 16 import {useMyListsQuery} from '#/state/queries/my-lists' 18 17 import {useGetPost} from '#/state/queries/post' ··· 52 51 import {CloseQuote_Stroke2_Corner1_Rounded as QuoteIcon} from '#/components/icons/Quote' 53 52 import {Loader} from '#/components/Loader' 54 53 import {Text} from '#/components/Typography' 54 + import {IS_IOS} from '#/env' 55 55 56 56 export type PostInteractionSettingsFormProps = { 57 57 canSave?: boolean ··· 531 531 hitSlop={0} 532 532 onPress={() => { 533 533 playHaptic('Light') 534 - if (isIOS && !showLists) { 534 + if (IS_IOS && !showLists) { 535 535 LayoutAnimation.configureNext({ 536 536 ...LayoutAnimation.Presets.linear, 537 537 duration: 175,
+4 -4
src/components/dialogs/SearchablePeopleList.tsx
··· 13 13 14 14 import {sanitizeDisplayName} from '#/lib/strings/display-names' 15 15 import {sanitizeHandle} from '#/lib/strings/handles' 16 - import {isWeb} from '#/platform/detection' 17 16 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 18 17 import {useModerationOpts} from '#/state/preferences/moderation-opts' 19 18 import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' ··· 30 29 import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' 31 30 import * as ProfileCard from '#/components/ProfileCard' 32 31 import {Text} from '#/components/Typography' 32 + import {IS_WEB} from '#/env' 33 33 import type * as bsky from '#/types/bsky' 34 34 35 35 export type ProfileItem = { ··· 257 257 ) 258 258 259 259 useLayoutEffect(() => { 260 - if (isWeb) { 260 + if (IS_WEB) { 261 261 setImmediate(() => { 262 262 inputRef?.current?.focus() 263 263 }) ··· 293 293 ]}> 294 294 {title} 295 295 </Text> 296 - {isWeb ? ( 296 + {IS_WEB ? ( 297 297 <Button 298 298 label={_(msg`Close`)} 299 299 size="small" 300 300 shape={enableSquareButtons ? 'square' : 'round'} 301 - variant={isWeb ? 'ghost' : 'solid'} 301 + variant={IS_WEB ? 'ghost' : 'solid'} 302 302 color="secondary" 303 303 style={[ 304 304 a.absolute,
+3 -3
src/components/dialogs/Signin.tsx
··· 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {isNative} from '#/platform/detection' 7 6 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 8 7 import {useCloseAllActiveElements} from '#/state/util' 9 8 import {Logo} from '#/view/icons/Logo' ··· 13 12 import * as Dialog from '#/components/Dialog' 14 13 import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' 15 14 import {Text} from '#/components/Typography' 15 + import {IS_NATIVE} from '#/env' 16 16 17 17 export function SigninDialog() { 18 18 const {signinDialogControl: control} = useGlobalDialogsControlContext() ··· 45 45 <Dialog.ScrollableInner 46 46 label={_(msg`Sign in to Bluesky or create a new account`)} 47 47 style={[gtMobile ? {width: 'auto', maxWidth: 420} : a.w_full]}> 48 - <View style={[!isNative && a.p_2xl]}> 48 + <View style={[!IS_NATIVE && a.p_2xl]}> 49 49 <View 50 50 style={[ 51 51 a.flex_row, ··· 101 101 </Button> 102 102 </View> 103 103 104 - {isNative && <View style={{height: 10}} />} 104 + {IS_NATIVE && <View style={{height: 10}} />} 105 105 </View> 106 106 107 107 <Dialog.Close />
+4 -4
src/components/dialogs/StarterPackDialog.tsx
··· 12 12 import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification' 13 13 import {type NavigationProp} from '#/lib/routes/types' 14 14 import {logger} from '#/logger' 15 - import {isWeb} from '#/platform/detection' 16 15 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 17 16 import { 18 17 invalidateActorStarterPacksWithMembershipQuery, ··· 33 32 import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' 34 33 import {Loader} from '#/components/Loader' 35 34 import {Text} from '#/components/Typography' 35 + import {IS_WEB} from '#/env' 36 36 import * as bsky from '#/types/bsky' 37 37 38 38 type StarterPackWithMembership = ··· 92 92 const t = useTheme() 93 93 94 94 return ( 95 - <View style={[a.gap_2xl, {paddingTop: isWeb ? 100 : 64}]}> 95 + <View style={[a.gap_2xl, {paddingTop: IS_WEB ? 100 : 64}]}> 96 96 <View style={[a.gap_xs, a.align_center]}> 97 97 <StarterPack 98 98 width={48} ··· 172 172 <View 173 173 style={[ 174 174 {justifyContent: 'space-between', flexDirection: 'row'}, 175 - isWeb ? a.mb_2xl : a.my_lg, 175 + IS_WEB ? a.mb_2xl : a.my_lg, 176 176 a.align_center, 177 177 ]}> 178 178 <Text style={[a.text_lg, a.font_semi_bold]}> ··· 235 235 onEndReachedThreshold={0.1} 236 236 ListHeaderComponent={listHeader} 237 237 ListEmptyComponent={<Empty onStartWizard={onStartWizard} />} 238 - style={isWeb ? [a.px_md, {minHeight: 500}] : [a.px_2xl, a.pt_lg]} 238 + style={IS_WEB ? [a.px_md, {minHeight: 500}] : [a.px_2xl, a.pt_lg]} 239 239 /> 240 240 ) 241 241 }
+2 -2
src/components/dialogs/lists/CreateOrEditListDialog.tsx
··· 9 9 import {richTextToString} from '#/lib/strings/rich-text-helpers' 10 10 import {shortenLinks, stripInvalidMentions} from '#/lib/strings/rich-text-manip' 11 11 import {logger} from '#/logger' 12 - import {isWeb} from '#/platform/detection' 13 12 import {type ImageMeta} from '#/state/gallery' 14 13 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 15 14 import { ··· 27 26 import {Loader} from '#/components/Loader' 28 27 import * as Prompt from '#/components/Prompt' 29 28 import {Text} from '#/components/Typography' 29 + import {IS_WEB} from '#/env' 30 30 31 31 const DISPLAY_NAME_MAX_GRAPHEMES = 64 32 32 const DESCRIPTION_MAX_GRAPHEMES = 300 ··· 49 49 50 50 // 'You might lose unsaved changes' warning 51 51 useEffect(() => { 52 - if (isWeb && dirty) { 52 + if (IS_WEB && dirty) { 53 53 const abortController = new AbortController() 54 54 const {signal} = abortController 55 55 window.addEventListener('beforeunload', evt => evt.preventDefault(), {
+6 -6
src/components/dialogs/nuxs/ActivitySubscriptions.tsx
··· 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {isWeb} from '#/platform/detection' 8 7 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 9 8 import {atoms as a, useTheme, web} from '#/alf' 10 9 import {Button, ButtonText} from '#/components/Button' ··· 12 11 import {useNuxDialogContext} from '#/components/dialogs/nuxs' 13 12 import {Sparkle_Stroke2_Corner0_Rounded as SparkleIcon} from '#/components/icons/Sparkle' 14 13 import {Text} from '#/components/Typography' 14 + import {IS_WEB} from '#/env' 15 15 16 16 export function ActivitySubscriptionsNUX() { 17 17 const t = useTheme() ··· 47 47 a.overflow_hidden, 48 48 t.atoms.bg_contrast_25, 49 49 { 50 - gap: isWeb ? 16 : 24, 51 - paddingTop: isWeb ? 24 : 48, 50 + gap: IS_WEB ? 16 : 24, 51 + paddingTop: IS_WEB ? 24 : 48, 52 52 borderTopLeftRadius: a.rounded_md.borderRadius, 53 53 borderTopRightRadius: a.rounded_md.borderRadius, 54 54 }, ··· 123 123 style={[ 124 124 a.align_center, 125 125 a.px_xl, 126 - isWeb ? [a.pt_xl, a.gap_xl, a.pb_sm] : [a.pt_3xl, a.gap_3xl], 126 + IS_WEB ? [a.pt_xl, a.gap_xl, a.pb_sm] : [a.pt_3xl, a.gap_3xl], 127 127 ]}> 128 128 <View style={[a.gap_md, a.align_center]}> 129 129 <Text ··· 133 133 a.font_bold, 134 134 a.text_center, 135 135 { 136 - fontSize: isWeb ? 28 : 32, 136 + fontSize: IS_WEB ? 28 : 32, 137 137 maxWidth: 300, 138 138 }, 139 139 ]}> ··· 156 156 </Text> 157 157 </View> 158 158 159 - {!isWeb && ( 159 + {!IS_WEB && ( 160 160 <Button 161 161 label={_(msg`Close`)} 162 162 size="large"
+5 -5
src/components/dialogs/nuxs/BookmarksAnnouncement.tsx
··· 5 5 import {msg, Trans} from '@lingui/macro' 6 6 import {useLingui} from '@lingui/react' 7 7 8 - import {isWeb} from '#/platform/detection' 9 8 import {atoms as a, useTheme, web} from '#/alf' 10 9 import {transparentifyColor} from '#/alf/util/colorGeneration' 11 10 import {Button, ButtonText} from '#/components/Button' ··· 13 12 import {useNuxDialogContext} from '#/components/dialogs/nuxs' 14 13 import {Sparkle_Stroke2_Corner0_Rounded as SparkleIcon} from '#/components/icons/Sparkle' 15 14 import {Text} from '#/components/Typography' 15 + import {IS_WEB} from '#/env' 16 16 17 17 export function BookmarksAnnouncement() { 18 18 const t = useTheme() ··· 49 49 a.overflow_hidden, 50 50 { 51 51 gap: 16, 52 - paddingTop: isWeb ? 24 : 40, 52 + paddingTop: IS_WEB ? 24 : 40, 53 53 borderTopLeftRadius: a.rounded_md.borderRadius, 54 54 borderTopRightRadius: a.rounded_md.borderRadius, 55 55 }, ··· 90 90 borderRadius: 24, 91 91 aspectRatio: 333 / 104, 92 92 }, 93 - isWeb 93 + IS_WEB 94 94 ? [ 95 95 { 96 96 boxShadow: `0px 10px 15px -3px ${transparentifyColor(t.palette.black, 0.2)}`, ··· 136 136 a.font_bold, 137 137 a.text_center, 138 138 { 139 - fontSize: isWeb ? 28 : 32, 139 + fontSize: IS_WEB ? 28 : 32, 140 140 maxWidth: 300, 141 141 }, 142 142 ]}> ··· 158 158 </Text> 159 159 </View> 160 160 161 - {!isWeb && ( 161 + {!IS_WEB && ( 162 162 <Button 163 163 label={_(msg`Close`)} 164 164 size="large"
+3 -3
src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
··· 6 6 import {useLingui} from '@lingui/react' 7 7 8 8 import {logger} from '#/logger' 9 - import {isNative, isWeb} from '#/platform/detection' 10 9 import {atoms as a, useTheme, web} from '#/alf' 11 10 import {Button, ButtonText} from '#/components/Button' 12 11 import {isFindContactsFeatureEnabled} from '#/components/contacts/country-allowlist' ··· 17 16 isExistingUserAsOf, 18 17 } from '#/components/dialogs/nuxs/utils' 19 18 import {Text} from '#/components/Typography' 19 + import {IS_NATIVE, IS_WEB} from '#/env' 20 20 import {IS_E2E} from '#/env' 21 21 import {navigate} from '#/Navigation' 22 22 23 23 export const enabled = createIsEnabledCheck(props => { 24 24 return ( 25 25 !IS_E2E && 26 - isNative && 26 + IS_NATIVE && 27 27 isExistingUserAsOf( 28 28 '2025-12-16T00:00:00.000Z', 29 29 props.currentProfile.createdAt, ··· 89 89 a.font_bold, 90 90 a.text_center, 91 91 { 92 - fontSize: isWeb ? 28 : 32, 92 + fontSize: IS_WEB ? 28 : 32, 93 93 maxWidth: 300, 94 94 }, 95 95 ]}>
+2 -2
src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx
··· 6 6 7 7 import {urls} from '#/lib/constants' 8 8 import {logger} from '#/logger' 9 - import {isNative} from '#/platform/detection' 10 9 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 11 10 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 12 11 import {Button, ButtonText} from '#/components/Button' ··· 16 15 import {VerifierCheck} from '#/components/icons/VerifierCheck' 17 16 import {Link} from '#/components/Link' 18 17 import {Span, Text} from '#/components/Typography' 18 + import {IS_NATIVE} from '#/env' 19 19 20 20 export function InitialVerificationAnnouncement() { 21 21 const t = useTheme() ··· 176 176 <Trans>Read blog post</Trans> 177 177 </ButtonText> 178 178 </Link> 179 - {isNative && ( 179 + {IS_NATIVE && ( 180 180 <Button 181 181 label={_(msg`Close`)} 182 182 size="small"
+6 -6
src/components/dialogs/nuxs/LiveNowBetaDialog.tsx
··· 5 5 import {msg, Trans} from '@lingui/macro' 6 6 import {useLingui} from '@lingui/react' 7 7 8 - import {isWeb} from '#/platform/detection' 9 8 import {atoms as a, select, useTheme, utils, web} from '#/alf' 10 9 import {Button, ButtonText} from '#/components/Button' 11 10 import * as Dialog from '#/components/Dialog' ··· 16 15 } from '#/components/dialogs/nuxs/utils' 17 16 import {Beaker_Stroke2_Corner2_Rounded as BeakerIcon} from '#/components/icons/Beaker' 18 17 import {Text} from '#/components/Typography' 18 + import {IS_WEB} from '#/env' 19 19 import {IS_E2E} from '#/env' 20 20 21 21 export const enabled = createIsEnabledCheck(props => { ··· 25 25 '2026-01-16T00:00:00.000Z', 26 26 props.currentProfile.createdAt, 27 27 ) && 28 - props.gate('live_now_beta') 28 + !props.gate('disable_live_now_beta') 29 29 ) 30 30 }) 31 31 ··· 72 72 a.overflow_hidden, 73 73 { 74 74 gap: 16, 75 - paddingTop: isWeb ? 24 : 40, 75 + paddingTop: IS_WEB ? 24 : 40, 76 76 borderTopLeftRadius: a.rounded_md.borderRadius, 77 77 borderTopRightRadius: a.rounded_md.borderRadius, 78 78 }, ··· 116 116 borderRadius: 24, 117 117 aspectRatio: 652 / 211, 118 118 }, 119 - isWeb 119 + IS_WEB 120 120 ? [ 121 121 { 122 122 boxShadow: `0px 10px 15px -3px ${shadowColor}`, ··· 163 163 a.font_bold, 164 164 a.text_center, 165 165 { 166 - fontSize: isWeb ? 28 : 32, 166 + fontSize: IS_WEB ? 28 : 32, 167 167 maxWidth: 360, 168 168 }, 169 169 ]}> ··· 186 186 </Text> 187 187 </View> 188 188 189 - {!isWeb && ( 189 + {!IS_WEB && ( 190 190 <Button 191 191 label={_(msg`Close`)} 192 192 size="large"
+1 -1
src/components/dms/ActionsWrapper.tsx
··· 21 21 <MessageContextMenu message={message}> 22 22 {trigger => 23 23 // will always be true, since this file is platform split 24 - trigger.isNative && ( 24 + trigger.IS_NATIVE && ( 25 25 <View style={[a.flex_1, a.relative]}> 26 26 <View 27 27 style={[
+4 -4
src/components/dms/ActionsWrapper.web.tsx
··· 92 92 : [a.ml_xs, {marginRight: 'auto'}], 93 93 ]}> 94 94 <EmojiReactionPicker message={message} onEmojiSelect={onEmojiSelect}> 95 - {({props, state, isNative, control}) => { 95 + {({props, state, IS_NATIVE, control}) => { 96 96 // always false, file is platform split 97 - if (isNative) return null 97 + if (IS_NATIVE) return null 98 98 const showMenuTrigger = showActions || control.isOpen ? 1 : 0 99 99 return ( 100 100 <Pressable ··· 114 114 }} 115 115 </EmojiReactionPicker> 116 116 <MessageContextMenu message={message}> 117 - {({props, state, isNative, control}) => { 117 + {({props, state, IS_NATIVE, control}) => { 118 118 // always false, file is platform split 119 - if (isNative) return null 119 + if (IS_NATIVE) return null 120 120 const showMenuTrigger = showActions || control.isOpen ? 1 : 0 121 121 return ( 122 122 <Pressable
+2 -2
src/components/dms/AfterReportDialog.tsx
··· 7 7 import type React from 'react' 8 8 9 9 import {type NavigationProp} from '#/lib/routes/types' 10 - import {isNative} from '#/platform/detection' 11 10 import {useProfileShadow} from '#/state/cache/profile-shadow' 12 11 import {useLeaveConvo} from '#/state/queries/messages/leave-conversation' 13 12 import { ··· 21 20 import * as Toggle from '#/components/forms/Toggle' 22 21 import {Loader} from '#/components/Loader' 23 22 import {Text} from '#/components/Typography' 23 + import {IS_NATIVE} from '#/env' 24 24 25 25 type ReportDialogParams = { 26 26 convoId: string ··· 130 130 onMutate: () => { 131 131 if (currentScreen === 'conversation') { 132 132 navigation.dispatch( 133 - StackActions.replace('Messages', isNative ? {animation: 'pop'} : {}), 133 + StackActions.replace('Messages', IS_NATIVE ? {animation: 'pop'} : {}), 134 134 ) 135 135 } 136 136 },
+3 -3
src/components/dms/ChatEmptyPill.tsx
··· 12 12 import {ScaleAndFadeIn} from '#/lib/custom-animations/ScaleAndFade' 13 13 import {ShrinkAndPop} from '#/lib/custom-animations/ShrinkAndPop' 14 14 import {useHaptics} from '#/lib/haptics' 15 - import {isWeb} from '#/platform/detection' 16 15 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 17 16 import {atoms as a, useTheme} from '#/alf' 18 17 import {Text} from '#/components/Typography' 18 + import {IS_WEB} from '#/env' 19 19 20 20 const AnimatedPressable = Animated.createAnimatedComponent(Pressable) 21 21 ··· 44 44 }, [_]) 45 45 46 46 const onPressIn = React.useCallback(() => { 47 - if (isWeb) return 47 + if (IS_WEB) return 48 48 scale.set(() => withTiming(1.075, {duration: 100})) 49 49 }, [scale]) 50 50 51 51 const onPressOut = React.useCallback(() => { 52 - if (isWeb) return 52 + if (IS_WEB) return 53 53 scale.set(() => withTiming(1, {duration: 100})) 54 54 }, [scale]) 55 55
+2 -2
src/components/dms/LeaveConvoPrompt.tsx
··· 3 3 import {StackActions, useNavigation} from '@react-navigation/native' 4 4 5 5 import {type NavigationProp} from '#/lib/routes/types' 6 - import {isNative} from '#/platform/detection' 7 6 import {useLeaveConvo} from '#/state/queries/messages/leave-conversation' 8 7 import * as Toast from '#/view/com/util/Toast' 9 8 import {type DialogOuterProps} from '#/components/Dialog' 10 9 import * as Prompt from '#/components/Prompt' 10 + import {IS_NATIVE} from '#/env' 11 11 12 12 export function LeaveConvoPrompt({ 13 13 control, ··· 27 27 onMutate: () => { 28 28 if (currentScreen === 'conversation') { 29 29 navigation.dispatch( 30 - StackActions.replace('Messages', isNative ? {animation: 'pop'} : {}), 30 + StackActions.replace('Messages', IS_NATIVE ? {animation: 'pop'} : {}), 31 31 ) 32 32 } 33 33 },
+2 -2
src/components/dms/MessageContextMenu.tsx
··· 8 8 import {useTranslate} from '#/lib/hooks/useTranslate' 9 9 import {richTextToString} from '#/lib/strings/rich-text-helpers' 10 10 import {logger} from '#/logger' 11 - import {isNative} from '#/platform/detection' 12 11 import {useConvoActive} from '#/state/messages/convo' 13 12 import {useLanguagePrefs} from '#/state/preferences' 14 13 import {useSession} from '#/state/session' ··· 23 22 import {ReportDialog} from '#/components/moderation/ReportDialog' 24 23 import * as Prompt from '#/components/Prompt' 25 24 import {usePromptControl} from '#/components/Prompt' 25 + import {IS_NATIVE} from '#/env' 26 26 import {EmojiReactionPicker} from './EmojiReactionPicker' 27 27 import {hasReachedReactionLimit} from './util' 28 28 ··· 112 112 return ( 113 113 <> 114 114 <ContextMenu.Root> 115 - {isNative && ( 115 + {IS_NATIVE && ( 116 116 <ContextMenu.AuxiliaryView align={isFromSelf ? 'right' : 'left'}> 117 117 <EmojiReactionPicker 118 118 message={message}
+3 -3
src/components/dms/MessageItem.tsx
··· 21 21 import {useLingui} from '@lingui/react' 22 22 23 23 import {sanitizeDisplayName} from '#/lib/strings/display-names' 24 - import {isNative} from '#/platform/detection' 25 24 import {useConvoActive} from '#/state/messages/convo' 26 25 import {type ConvoItem} from '#/state/messages/convo/types' 27 26 import {useSession} from '#/state/session' ··· 32 31 import {InlineLinkText} from '#/components/Link' 33 32 import {RichText} from '#/components/RichText' 34 33 import {Text} from '#/components/Typography' 34 + import {IS_NATIVE} from '#/env' 35 35 import {DateDivider} from './DateDivider' 36 36 import {MessageItemEmbed} from './MessageItemEmbed' 37 37 import {localDateString} from './util' ··· 218 218 </View> 219 219 )} 220 220 221 - {isNative && appliedReactions} 221 + {IS_NATIVE && appliedReactions} 222 222 </ActionsWrapper> 223 223 224 - {!isNative && appliedReactions} 224 + {!IS_NATIVE && appliedReactions} 225 225 226 226 {isLastInGroup && ( 227 227 <MessageItemMetadata
+2 -2
src/components/dms/MessagesListHeader.tsx
··· 10 10 11 11 import {makeProfileLink} from '#/lib/routes/links' 12 12 import {sanitizeDisplayName} from '#/lib/strings/display-names' 13 - import {isWeb} from '#/platform/detection' 14 13 import {type Shadow} from '#/state/cache/profile-shadow' 15 14 import {isConvoActive, useConvo} from '#/state/messages/convo' 16 15 import {type ConvoItem} from '#/state/messages/convo/types' ··· 24 23 import {Text} from '#/components/Typography' 25 24 import {useSimpleVerificationState} from '#/components/verification' 26 25 import {VerificationCheck} from '#/components/verification/VerificationCheck' 26 + import {IS_WEB} from '#/env' 27 27 28 - const PFP_SIZE = isWeb ? 40 : Layout.HEADER_SLOT_SIZE 28 + const PFP_SIZE = IS_WEB ? 40 : Layout.HEADER_SLOT_SIZE 29 29 30 30 export function MessagesListHeader({ 31 31 profile,
+5 -5
src/components/dms/NewMessagesPill.tsx
··· 14 14 ScaleAndFadeOut, 15 15 } from '#/lib/custom-animations/ScaleAndFade' 16 16 import {useHaptics} from '#/lib/haptics' 17 - import {isAndroid, isIOS, isWeb} from '#/platform/detection' 18 17 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 19 18 import {atoms as a, useTheme} from '#/alf' 20 19 import {Text} from '#/components/Typography' 20 + import {IS_ANDROID, IS_IOS, IS_WEB} from '#/env' 21 21 22 22 const AnimatedPressable = Animated.createAnimatedComponent(Pressable) 23 23 ··· 29 29 const t = useTheme() 30 30 const playHaptic = useHaptics() 31 31 const {bottom: bottomInset} = useSafeAreaInsets() 32 - const bottomBarHeight = isIOS ? 42 : isAndroid ? 60 : 0 33 - const bottomOffset = isWeb ? 0 : bottomInset + bottomBarHeight 32 + const bottomBarHeight = IS_IOS ? 42 : IS_ANDROID ? 60 : 0 33 + const bottomOffset = IS_WEB ? 0 : bottomInset + bottomBarHeight 34 34 35 35 const scale = useSharedValue(1) 36 36 37 37 const enableSquareButtons = useEnableSquareButtons() 38 38 39 39 const onPressIn = React.useCallback(() => { 40 - if (isWeb) return 40 + if (IS_WEB) return 41 41 scale.set(() => withTiming(1.075, {duration: 100})) 42 42 }, [scale]) 43 43 44 44 const onPressOut = React.useCallback(() => { 45 - if (isWeb) return 45 + if (IS_WEB) return 46 46 scale.set(() => withTiming(1, {duration: 100})) 47 47 }, [scale]) 48 48
+2 -2
src/components/forms/SearchInput.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {HITSLOP_10} from '#/lib/constants' 7 - import {isNative} from '#/platform/detection' 8 7 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 9 8 import {atoms as a, useTheme} from '#/alf' 10 9 import {Button, ButtonIcon} from '#/components/Button' 11 10 import * as TextField from '#/components/forms/TextField' 12 11 import {MagnifyingGlass_Stroke2_Corner0_Rounded as MagnifyingGlassIcon} from '#/components/icons/MagnifyingGlass' 13 12 import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' 13 + import {IS_NATIVE} from '#/env' 14 14 15 15 type SearchInputProps = Omit<TextField.InputProps, 'label'> & { 16 16 label?: TextField.InputProps['label'] ··· 39 39 placeholder={_(msg`Search`)} 40 40 returnKeyType="search" 41 41 keyboardAppearance={t.scheme} 42 - selectTextOnFocus={isNative} 42 + selectTextOnFocus={IS_NATIVE} 43 43 autoFocus={false} 44 44 accessibilityRole="search" 45 45 autoCorrect={false}
+2 -2
src/components/forms/TextField.tsx
··· 11 11 12 12 import {HITSLOP_20} from '#/lib/constants' 13 13 import {mergeRefs} from '#/lib/merge-refs' 14 - import {isWeb} from '#/platform/detection' 15 14 import { 16 15 android, 17 16 applyFonts, ··· 26 25 import {useInteractionState} from '#/components/hooks/useInteractionState' 27 26 import {type Props as SVGIconProps} from '#/components/icons/common' 28 27 import {Text} from '#/components/Typography' 28 + import {IS_WEB} from '#/env/index.web' 29 29 30 30 const Context = createContext<{ 31 31 inputRef: React.RefObject<TextInput | null> | null ··· 106 106 a.align_center, 107 107 a.relative, 108 108 a.w_full, 109 - !(hasMultiline && isWeb) && a.px_md, 109 + !(hasMultiline && IS_WEB) && a.px_md, 110 110 style, 111 111 ]} 112 112 {...web({
+2 -2
src/components/forms/Toggle/index.tsx
··· 10 10 11 11 import {HITSLOP_10} from '#/lib/constants' 12 12 import {useHaptics} from '#/lib/haptics' 13 - import {isNative} from '#/platform/detection' 14 13 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 15 14 import { 16 15 atoms as a, ··· 23 22 import {useInteractionState} from '#/components/hooks/useInteractionState' 24 23 import {CheckThick_Stroke2_Corner0_Rounded as Checkmark} from '#/components/icons/Check' 25 24 import {Text} from '#/components/Typography' 25 + import {IS_NATIVE} from '#/env' 26 26 27 27 export * from './Panel' 28 28 ··· 564 564 ) 565 565 } 566 566 567 - export const Platform = isNative ? Switch : Checkbox 567 + export const Platform = IS_NATIVE ? Switch : Checkbox
+3 -4
src/components/hooks/useFullscreen.ts
··· 6 6 useSyncExternalStore, 7 7 } from 'react' 8 8 9 - import {isFirefox, isSafari} from '#/lib/browser' 10 - import {isWeb} from '#/platform/detection' 9 + import {IS_WEB, IS_WEB_FIREFOX, IS_WEB_SAFARI} from '#/env' 11 10 12 11 function fullscreenSubscribe(onChange: () => void) { 13 12 document.addEventListener('fullscreenchange', onChange) ··· 15 14 } 16 15 17 16 export function useFullscreen(ref?: React.RefObject<HTMLElement | null>) { 18 - if (!isWeb) throw new Error("'useFullscreen' is a web-only hook") 17 + if (!IS_WEB) throw new Error("'useFullscreen' is a web-only hook") 19 18 const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () => 20 19 Boolean(document.fullscreenElement), 21 20 ) ··· 39 38 40 39 // Chrome has an issue where it doesn't scroll back to the top after exiting fullscreen 41 40 // Let's play it safe and do it if not FF or Safari, since anything else will probably be chromium 42 - if (prevIsFullscreen && !isFirefox && !isSafari) { 41 + if (prevIsFullscreen && !IS_WEB_FIREFOX && !IS_WEB_SAFARI) { 43 42 setTimeout(() => { 44 43 if (scrollYRef.current !== null) { 45 44 window.scrollTo(0, scrollYRef.current)
+2 -2
src/components/hooks/useStarterPackEntry.native.ts
··· 4 4 createStarterPackLinkFromAndroidReferrer, 5 5 httpStarterPackUriToAtUri, 6 6 } from '#/lib/strings/starter-pack' 7 - import {isAndroid} from '#/platform/detection' 8 7 import {useHasCheckedForStarterPack} from '#/state/preferences/used-starter-packs' 9 8 import {useSetActiveStarterPack} from '#/state/shell/starter-pack' 9 + import {IS_ANDROID} from '#/env' 10 10 import {Referrer, SharedPrefs} from '../../../modules/expo-bluesky-swiss-army' 11 11 12 12 export function useStarterPackEntry() { ··· 32 32 ;(async () => { 33 33 let uri: string | null | undefined 34 34 35 - if (isAndroid) { 35 + if (IS_ANDROID) { 36 36 const res = await Referrer.getGooglePlayReferrerInfoAsync() 37 37 38 38 if (res && res.installReferrer) {
+2 -2
src/components/hooks/useWelcomeModal.ts
··· 1 1 import {useEffect, useState} from 'react' 2 2 3 - import {isWeb} from '#/platform/detection' 4 3 import {useSession} from '#/state/session' 4 + import {IS_WEB} from '#/env' 5 5 6 6 export function useWelcomeModal() { 7 7 const {hasSession} = useSession() ··· 22 22 // 2. We're on the web (this is a web-only feature) 23 23 // 3. We're on the homepage (path is '/' or '/home') 24 24 // 4. User hasn't actively closed the modal in this session 25 - if (isWeb && !hasSession && typeof window !== 'undefined') { 25 + if (IS_WEB && !hasSession && typeof window !== 'undefined') { 26 26 const currentPath = window.location.pathname 27 27 const isHomePage = currentPath === '/' 28 28 const hasUserClosedModal =
+2 -2
src/components/images/AutoSizedImage.tsx
··· 11 11 import {useLingui} from '@lingui/react' 12 12 13 13 import {type Dimensions} from '#/lib/media/types' 14 - import {isNative} from '#/platform/detection' 15 14 import { 16 15 maybeModifyHighQualityImage, 17 16 useHighQualityImages, ··· 21 20 import {ArrowsDiagonalOut_Stroke2_Corner0_Rounded as Fullscreen} from '#/components/icons/ArrowsDiagonal' 22 21 import {MediaInsetBorder} from '#/components/MediaInsetBorder' 23 22 import {Text} from '#/components/Typography' 23 + import {IS_NATIVE} from '#/env' 24 24 25 25 export function ConstrainedImage({ 26 26 aspectRatio, ··· 39 39 * the height of the image. 40 40 */ 41 41 const outerAspectRatio = useMemo<DimensionValue>(() => { 42 - const ratio = isNative 42 + const ratio = IS_NATIVE 43 43 ? Math.min(1 / aspectRatio, minMobileAspectRatio ?? 16 / 9) // 9:16 bounding box 44 44 : Math.min(1 / aspectRatio, 1) // 1:1 bounding box 45 45 return `${ratio * 100}%`
+3 -3
src/components/intents/VerifyEmailIntentDialog.tsx
··· 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {isNative} from '#/platform/detection' 7 6 import {useAgent, useSession} from '#/state/session' 8 7 import {pdsAgent} from '#/state/session/agent' 9 8 import {atoms as a, useBreakpoints, useTheme} from '#/alf' ··· 16 15 import {useIntentDialogs} from '#/components/intents/IntentDialogs' 17 16 import {Loader} from '#/components/Loader' 18 17 import {Text} from '#/components/Typography' 18 + import {IS_NATIVE} from '#/env' 19 19 20 20 export function VerifyEmailIntentDialog() { 21 21 const {verifyEmailDialogControl: control} = useIntentDialogs() ··· 69 69 <Loader size="xl" fill={t.atoms.text_contrast_low.color} /> 70 70 </View> 71 71 ) : status === 'success' ? ( 72 - <View style={[a.gap_sm, isNative && a.pb_xl]}> 72 + <View style={[a.gap_sm, IS_NATIVE && a.pb_xl]}> 73 73 <Text style={[a.font_bold, a.text_2xl]}> 74 74 <Trans>Email Verified</Trans> 75 75 </Text> ··· 94 94 </Text> 95 95 </View> 96 96 ) : ( 97 - <View style={[a.gap_sm, isNative && a.pb_xl]}> 97 + <View style={[a.gap_sm, IS_NATIVE && a.pb_xl]}> 98 98 <Text style={[a.font_bold, a.text_2xl]}> 99 99 <Trans>Email Resent</Trans> 100 100 </Text>
+1 -1
src/components/live/EditLiveDialog.tsx
··· 98 98 } = useRemoveLiveStatusMutation() 99 99 100 100 const {minutesUntilExpiry, expiryDateTime} = useMemo(() => { 101 - tick! 101 + void tick 102 102 103 103 const expiry = new Date(status.expiresAt ?? new Date()) 104 104 return {
+6 -3
src/components/live/GoLiveDialog.tsx
··· 13 13 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 14 14 import * as Dialog from '#/components/Dialog' 15 15 import * as TextField from '#/components/forms/TextField' 16 - import {getLiveServiceNames} from '#/components/live/utils' 16 + import { 17 + displayDuration, 18 + getLiveServiceNames, 19 + useDebouncedValue, 20 + } from '#/components/live/utils' 17 21 import {Loader} from '#/components/Loader' 18 22 import * as ProfileCard from '#/components/ProfileCard' 19 23 import * as Select from '#/components/Select' ··· 21 25 import type * as bsky from '#/types/bsky' 22 26 import {LinkPreview} from './LinkPreview' 23 27 import {useLiveLinkMetaQuery, useUpsertLiveStatusMutation} from './queries' 24 - import {displayDuration, useDebouncedValue} from './utils' 25 28 26 29 export function GoLiveDialog({ 27 30 control, ··· 57 60 58 61 const time = useCallback( 59 62 (offset: number) => { 60 - tick! 63 + void tick 61 64 62 65 const date = new Date() 63 66 date.setMinutes(date.getMinutes() + offset)
+2 -2
src/components/moderation/LabelsOnMeDialog.tsx
··· 12 12 import {makeProfileLink} from '#/lib/routes/links' 13 13 import {sanitizeHandle} from '#/lib/strings/handles' 14 14 import {logger} from '#/logger' 15 - import {isAndroid} from '#/platform/detection' 16 15 import {useAgent, useSession} from '#/state/session' 17 16 import * as Toast from '#/view/com/util/Toast' 18 17 import {atoms as a, useBreakpoints, useTheme} from '#/alf' ··· 20 19 import * as Dialog from '#/components/Dialog' 21 20 import {InlineLinkText} from '#/components/Link' 22 21 import {Text} from '#/components/Typography' 22 + import {IS_ANDROID} from '#/env' 23 23 import {Admonition} from '../Admonition' 24 24 import {Divider} from '../Divider' 25 25 import {Loader} from '../Loader' ··· 344 344 {isPending && <ButtonIcon icon={Loader} />} 345 345 </Button> 346 346 </View> 347 - {isAndroid && <View style={{height: 300}} />} 347 + {IS_ANDROID && <View style={{height: 300}} />} 348 348 </> 349 349 ) 350 350 }
+3 -3
src/components/moderation/ModerationDetailsDialog.tsx
··· 7 7 import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' 8 8 import {makeProfileLink} from '#/lib/routes/links' 9 9 import {listUriToHref} from '#/lib/strings/url-helpers' 10 - import {isNative} from '#/platform/detection' 11 10 import {useSession} from '#/state/session' 12 11 import {atoms as a, useGutters, useTheme} from '#/alf' 13 12 import * as Dialog from '#/components/Dialog' 14 13 import {InlineLinkText} from '#/components/Link' 15 14 import {type AppModerationCause} from '#/components/Pills' 16 15 import {Text} from '#/components/Typography' 16 + import {IS_NATIVE} from '#/env' 17 17 18 18 export {useDialogControl as useModerationDetailsDialogControl} from '#/components/Dialog' 19 19 ··· 158 158 xGutters, 159 159 a.py_md, 160 160 a.border_t, 161 - !isNative && t.atoms.bg_contrast_25, 161 + !IS_NATIVE && t.atoms.bg_contrast_25, 162 162 t.atoms.border_contrast_low, 163 163 { 164 164 borderBottomLeftRadius: a.rounded_md.borderRadius, ··· 219 219 </View> 220 220 )} 221 221 222 - {isNative && <View style={{height: 40}} />} 222 + {IS_NATIVE && <View style={{height: 40}} />} 223 223 224 224 <Dialog.Close /> 225 225 </Dialog.ScrollableInner>
+4 -4
src/components/moderation/ReportDialog/index.tsx
··· 8 8 import {getLabelingServiceTitle} from '#/lib/moderation' 9 9 import {sanitizeHandle} from '#/lib/strings/handles' 10 10 import {Logger} from '#/logger' 11 - import {isNative} from '#/platform/detection' 12 11 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 13 12 import {useMyLabelersQuery} from '#/state/queries/preferences' 14 13 import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' ··· 30 29 import {createStaticClick, InlineLinkText, Link} from '#/components/Link' 31 30 import {Loader} from '#/components/Loader' 32 31 import {Text} from '#/components/Typography' 32 + import {IS_NATIVE} from '#/env' 33 33 import {useSubmitReportMutation} from './action' 34 34 import { 35 35 BSKY_LABELER_ONLY_REPORT_REASONS, ··· 214 214 logger.metric( 215 215 'reportDialog:success', 216 216 { 217 - reason: state.selectedOption?.reason!, 218 - labeler: state.selectedLabeler?.creator.handle!, 217 + reason: state.selectedOption?.reason ?? '', 218 + labeler: state.selectedLabeler?.creator.handle ?? '', 219 219 details: !!state.details, 220 220 }, 221 221 {statsig: false}, ··· 256 256 label={_(msg`Report dialog`)} 257 257 ref={ref} 258 258 style={[a.w_full, {maxWidth: 500}]}> 259 - <View style={[a.gap_2xl, isNative && a.pt_md]}> 259 + <View style={[a.gap_2xl, IS_NATIVE && a.pt_md]}> 260 260 <StepOuter> 261 261 <StepTitle 262 262 index={1}
+24
src/env/index.ts
··· 1 + import {Platform} from 'react-native' 1 2 import {nativeBuildVersion} from 'expo-application' 2 3 3 4 import {BUNDLE_IDENTIFIER, IS_TESTFLIGHT, RELEASE_VERSION} from '#/env/common' ··· 17 18 export const APP_METADATA = `${BUNDLE_IDENTIFIER.slice(0, 7)} (${ 18 19 __DEV__ ? 'dev' : IS_TESTFLIGHT ? 'tf' : 'prod' 19 20 })` 21 + 22 + /** 23 + * Platform detection 24 + */ 25 + export const IS_IOS: boolean = Platform.OS === 'ios' 26 + export const IS_ANDROID: boolean = Platform.OS === 'android' 27 + export const IS_NATIVE: boolean = true 28 + export const IS_WEB: boolean = false 29 + 30 + /** 31 + * Web-specific platform detection 32 + */ 33 + export const IS_WEB_TOUCH_DEVICE: boolean = true 34 + export const IS_WEB_MOBILE: boolean = false 35 + export const IS_WEB_MOBILE_IOS: boolean = false 36 + export const IS_WEB_MOBILE_ANDROID: boolean = false 37 + export const IS_WEB_SAFARI: boolean = false 38 + export const IS_WEB_FIREFOX: boolean = false 39 + 40 + /** 41 + * Misc 42 + */ 43 + export const IS_HIGH_DPI: boolean = true
+34
src/env/index.web.ts
··· 13 13 * The short commit hash and environment of the current bundle. 14 14 */ 15 15 export const APP_METADATA = `${BUNDLE_IDENTIFIER.slice(0, 7)} (${__DEV__ ? 'dev' : 'prod'})` 16 + 17 + /** 18 + * Platform detection 19 + */ 20 + export const IS_IOS: boolean = false 21 + export const IS_ANDROID: boolean = false 22 + export const IS_NATIVE: boolean = false 23 + export const IS_WEB: boolean = true 24 + 25 + /** 26 + * Web-specific platform detection 27 + */ 28 + export const IS_WEB_TOUCH_DEVICE = 29 + window.matchMedia('(pointer: coarse)').matches 30 + export const IS_WEB_MOBILE: boolean = window.matchMedia( 31 + 'only screen and (max-width: 1300px)', 32 + )?.matches 33 + export const IS_WEB_MOBILE_IOS: boolean = /iPhone/.test(navigator.userAgent) 34 + export const IS_WEB_MOBILE_ANDROID: boolean = 35 + /android/i.test(navigator.userAgent) && IS_WEB_TOUCH_DEVICE 36 + export const IS_WEB_SAFARI: boolean = /^((?!chrome|android).)*safari/i.test( 37 + // https://stackoverflow.com/questions/7944460/detect-safari-browser 38 + navigator.userAgent, 39 + ) 40 + export const IS_WEB_FIREFOX: boolean = /firefox|fxios/i.test( 41 + navigator.userAgent, 42 + ) 43 + 44 + /** 45 + * Misc 46 + */ 47 + export const IS_HIGH_DPI: boolean = window.matchMedia( 48 + '(min-resolution: 2dppx)', 49 + ).matches
+12 -14
src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx
··· 3 3 import {useLingui} from '@lingui/react' 4 4 5 5 import {useCleanError} from '#/lib/hooks/useCleanError' 6 - import {isNative} from '#/platform/detection' 7 6 import {atoms as a, web} from '#/alf' 8 7 import {Admonition} from '#/components/Admonition' 9 8 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 10 9 import * as Dialog from '#/components/Dialog' 11 10 import {Loader} from '#/components/Loader' 12 - import * as toast from '#/components/Toast' 11 + import * as Toast from '#/components/Toast' 13 12 import {Span, Text} from '#/components/Typography' 13 + import {IS_NATIVE} from '#/env' 14 14 import {useUpdateLiveEventPreferences} from '#/features/liveEvents/preferences' 15 15 import { 16 16 type LiveEventFeed, ··· 61 61 feed, 62 62 metricContext, 63 63 onUpdateSuccess({undoAction}) { 64 - toast.show( 65 - <toast.Outer> 66 - <toast.Icon /> 67 - <toast.Text> 64 + Toast.show( 65 + <Toast.Outer> 66 + <Toast.Icon /> 67 + <Toast.Text> 68 68 <Trans>Your live event preferences have been updated.</Trans> 69 - </toast.Text> 69 + </Toast.Text> 70 70 {undoAction && ( 71 - <toast.Action 71 + <Toast.Action 72 72 label={_(msg`Undo`)} 73 73 onPress={() => { 74 74 if (undoAction) { ··· 76 76 } 77 77 }}> 78 78 <Trans>Undo</Trans> 79 - </toast.Action> 79 + </Toast.Action> 80 80 )} 81 - </toast.Outer>, 82 - { 83 - type: 'success', 84 - }, 81 + </Toast.Outer>, 82 + {type: 'success'}, 85 83 ) 86 84 87 85 /* ··· 148 146 </ButtonText> 149 147 {isHidingAllFeeds && <ButtonIcon icon={Loader} />} 150 148 </Button> 151 - {isNative && ( 149 + {IS_NATIVE && ( 152 150 <Button 153 151 label={_(msg`Cancel`)} 154 152 size="large"
+2 -2
src/features/liveEvents/preferences.ts
··· 3 3 import {useMutation, useQueryClient} from '@tanstack/react-query' 4 4 5 5 import {logger} from '#/logger' 6 - import {isWeb} from '#/platform/detection' 7 6 import { 8 7 preferencesQueryKey, 9 8 usePreferencesQuery, 10 9 } from '#/state/queries/preferences' 11 10 import {useAgent} from '#/state/session' 11 + import {IS_WEB} from '#/env' 12 12 import * as env from '#/env' 13 13 import { 14 14 type LiveEventFeed, ··· 41 41 const agent = useAgent() 42 42 43 43 useEffect(() => { 44 - if (env.IS_DEV && isWeb && typeof window !== 'undefined') { 44 + if (env.IS_DEV && IS_WEB && typeof window !== 'undefined') { 45 45 // @ts-ignore 46 46 window.__updateLiveEventPreferences = async ( 47 47 action: LiveEventPreferencesAction,
+2 -2
src/geolocation/device.ts
··· 3 3 import * as Location from 'expo-location' 4 4 import {createPermissionHook} from 'expo-modules-core' 5 5 6 - import {isNative} from '#/platform/detection' 6 + import {IS_NATIVE} from '#/env' 7 7 import * as debug from '#/geolocation/debug' 8 8 import {logger} from '#/geolocation/logger' 9 9 import {type Geolocation} from '#/geolocation/types' ··· 118 118 const synced = useRef(false) 119 119 const [status] = useForegroundPermissions() 120 120 useEffect(() => { 121 - if (!isNative) return 121 + if (!IS_NATIVE) return 122 122 123 123 async function get() { 124 124 // no need to set this more than once per session
+2 -2
src/geolocation/service.ts
··· 127 127 }) 128 128 129 129 useEffect(() => { 130 - return onGeolocationServiceResponseUpdate(responseConfig => { 131 - setConfig(responseConfig!) 130 + return onGeolocationServiceResponseUpdate(config => { 131 + setConfig(config) 132 132 }) 133 133 }, []) 134 134
+2 -2
src/geolocation/util.ts
··· 1 1 import {type LocationGeocodedAddress} from 'expo-location' 2 2 3 - import {isAndroid} from '#/platform/detection' 3 + import {IS_ANDROID} from '#/env' 4 4 import {logger} from '#/geolocation/logger' 5 5 import {type Geolocation} from '#/geolocation/types' 6 6 ··· 81 81 /* 82 82 * Android doesn't give us ISO 3166-2 short codes. We need these for US 83 83 */ 84 - if (isAndroid) { 84 + if (IS_ANDROID) { 85 85 if (region && isoCountryCode === 'US') { 86 86 /* 87 87 * We need short codes for US states. If we can't remap it, just drop it
+1 -1
src/lib/actor-status.ts
··· 17 17 const config = useLiveNowConfig() 18 18 19 19 return useMemo(() => { 20 - tick! // revalidate every minute 20 + void tick // revalidate every minute 21 21 22 22 if (shadowed && 'status' in shadowed && shadowed.status) { 23 23 const isValid = validateStatus(shadowed.status, config)
+2 -2
src/lib/api/feed/utils.ts
··· 1 1 import {AtUri} from '@atproto/api' 2 2 3 3 import {BSKY_FEED_OWNER_DIDS} from '#/lib/constants' 4 - import {isWeb} from '#/platform/detection' 5 4 import {type UsePreferencesQueryResponse} from '#/state/queries/preferences' 5 + import {IS_WEB} from '#/env' 6 6 7 7 let debugTopics = '' 8 - if (isWeb && typeof window !== 'undefined') { 8 + if (IS_WEB && typeof window !== 'undefined') { 9 9 const params = new URLSearchParams(window.location.search) 10 10 debugTopics = params.get('debug_topics') ?? '' 11 11 }
-5
src/lib/browser.native.ts
··· 1 - export const isSafari = false 2 - export const isFirefox = false 3 - export const isTouchDevice = true 4 - export const isAndroidWeb = false 5 - export const isHighDPI = true
-9
src/lib/browser.ts
··· 1 - // https://stackoverflow.com/questions/7944460/detect-safari-browser 2 - export const isSafari = /^((?!chrome|android).)*safari/i.test( 3 - navigator.userAgent, 4 - ) 5 - export const isFirefox = /firefox|fxios/i.test(navigator.userAgent) 6 - export const isTouchDevice = window.matchMedia('(pointer: coarse)').matches 7 - export const isAndroidWeb = 8 - /android/i.test(navigator.userAgent) && isTouchDevice 9 - export const isHighDPI = window.matchMedia('(min-resolution: 2dppx)').matches
+3 -3
src/lib/custom-animations/AccordionAnimation.tsx
··· 13 13 withTiming, 14 14 } from 'react-native-reanimated' 15 15 16 - import {isIOS, isWeb} from '#/platform/detection' 16 + import {IS_IOS, IS_WEB} from '#/env' 17 17 18 18 type AccordionAnimationProps = React.PropsWithChildren<{ 19 19 isExpanded: boolean ··· 66 66 style={style} 67 67 entering={FadeInUp.duration(duration)} 68 68 exiting={FadeOutUp.duration(duration / 2)} 69 - pointerEvents={isIOS ? 'auto' : 'box-none'}> 69 + pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 70 70 {children} 71 71 </Animated.View> 72 72 ) 73 73 } 74 74 75 75 export function AccordionAnimation(props: AccordionAnimationProps) { 76 - return isWeb ? <WebAccordion {...props} /> : <MobileAccordion {...props} /> 76 + return IS_WEB ? <WebAccordion {...props} /> : <MobileAccordion {...props} /> 77 77 }
+2 -3
src/lib/custom-animations/PressableScale.tsx
··· 12 12 withTiming, 13 13 } from 'react-native-reanimated' 14 14 15 - import {isTouchDevice} from '#/lib/browser' 16 - import {isNative} from '#/platform/detection' 15 + import {IS_NATIVE, IS_WEB_TOUCH_DEVICE} from '#/env' 17 16 18 - const DEFAULT_TARGET_SCALE = isNative || isTouchDevice ? 0.98 : 1 17 + const DEFAULT_TARGET_SCALE = IS_NATIVE || IS_WEB_TOUCH_DEVICE ? 0.98 : 1 19 18 20 19 const AnimatedPressable = Animated.createAnimatedComponent(Pressable) 21 20
+1 -1
src/lib/functions.ts
··· 67 67 } 68 68 69 69 // Copied from: https://github.com/jonschlinkert/is-plain-object 70 - export function isPlainObject(o: any): o is Object { 70 + export function isPlainObject(o: any): o is object { 71 71 if (!hasObjectPrototype(o)) { 72 72 return false 73 73 }
+3 -3
src/lib/haptics.ts
··· 2 2 import * as Device from 'expo-device' 3 3 import {impactAsync, ImpactFeedbackStyle} from 'expo-haptics' 4 4 5 - import {isIOS, isWeb} from '#/platform/detection' 6 5 import {useHapticsDisabled} from '#/state/preferences/disable-haptics' 6 + import {IS_IOS, IS_WEB} from '#/env' 7 7 8 8 export function useHaptics() { 9 9 const isHapticsDisabled = useHapticsDisabled() 10 10 11 11 return React.useCallback( 12 12 (strength: 'Light' | 'Medium' | 'Heavy' = 'Medium') => { 13 - if (isHapticsDisabled || isWeb) { 13 + if (isHapticsDisabled || IS_WEB) { 14 14 return 15 15 } 16 16 17 17 // Users said the medium impact was too strong on Android; see APP-537s 18 - const style = isIOS 18 + const style = IS_IOS 19 19 ? ImpactFeedbackStyle[strength] 20 20 : ImpactFeedbackStyle.Light 21 21 impactAsync(style)
+2 -2
src/lib/hooks/useBottomBarOffset.ts
··· 2 2 3 3 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 4 4 import {clamp} from '#/lib/numbers' 5 - import {isWeb} from '#/platform/detection' 5 + import {IS_WEB} from '#/env' 6 6 7 7 export function useBottomBarOffset(modifier: number = 0) { 8 8 const {isTabletOrDesktop} = useWebMediaQueries() 9 9 const {bottom: bottomInset} = useSafeAreaInsets() 10 10 return ( 11 - (isWeb && isTabletOrDesktop ? 0 : clamp(60 + bottomInset, 60, 75)) + 11 + (IS_WEB && isTabletOrDesktop ? 0 : clamp(60 + bottomInset, 60, 75)) + 12 12 modifier 13 13 ) 14 14 }
+3 -3
src/lib/hooks/useIntentHandler.ts
··· 6 6 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 7 7 import {parseLinkingUrl} from '#/lib/parseLinkingUrl' 8 8 import {logger} from '#/logger' 9 - import {isIOS, isNative} from '#/platform/detection' 10 9 import {useSession} from '#/state/session' 11 10 import {useCloseAllActiveElements} from '#/state/util' 12 11 import {useIntentDialogs} from '#/components/intents/IntentDialogs' 12 + import {IS_IOS, IS_NATIVE} from '#/env' 13 13 import {Referrer} from '../../../modules/expo-bluesky-swiss-army' 14 14 import {useApplyPullRequestOTAUpdate} from './useOTAUpdates' 15 15 ··· 29 29 30 30 React.useEffect(() => { 31 31 const handleIncomingURL = async (url: string) => { 32 - if (isIOS) { 32 + if (IS_IOS) { 33 33 // Close in-app browser if it's open (iOS only) 34 34 await WebBrowser.dismissBrowser().catch(() => {}) 35 35 } ··· 150 150 setTimeout(() => { 151 151 openComposer({ 152 152 text: text ?? undefined, 153 - imageUris: isNative ? imageUris : undefined, 153 + imageUris: IS_NATIVE ? imageUris : undefined, 154 154 }) 155 155 }, 500) 156 156 },
+3 -3
src/lib/hooks/useIsKeyboardVisible.ts
··· 1 1 import {useEffect, useState} from 'react' 2 2 import {Keyboard} from 'react-native' 3 3 4 - import {isIOS} from '#/platform/detection' 4 + import {IS_IOS} from '#/env' 5 5 6 6 export function useIsKeyboardVisible({ 7 7 iosUseWillEvents, ··· 14 14 // only iOS supports the "will" events 15 15 // -prf 16 16 const showEvent = 17 - isIOS && iosUseWillEvents ? 'keyboardWillShow' : 'keyboardDidShow' 17 + IS_IOS && iosUseWillEvents ? 'keyboardWillShow' : 'keyboardDidShow' 18 18 const hideEvent = 19 - isIOS && iosUseWillEvents ? 'keyboardWillHide' : 'keyboardDidHide' 19 + IS_IOS && iosUseWillEvents ? 'keyboardWillHide' : 'keyboardDidHide' 20 20 21 21 useEffect(() => { 22 22 const keyboardShowListener = Keyboard.addListener(showEvent, () =>
+3 -3
src/lib/hooks/useNotificationHandler.ts
··· 9 9 import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher' 10 10 import {logger as notyLogger} from '#/lib/notifications/util' 11 11 import {type NavigationProp} from '#/lib/routes/types' 12 - import {isAndroid, isIOS} from '#/platform/detection' 13 12 import {useCurrentConvoId} from '#/state/messages/current-convo-id' 14 13 import {RQKEY as RQKEY_NOTIFS} from '#/state/queries/notifications/feed' 15 14 import {invalidateCachedUnreadPage} from '#/state/queries/notifications/unread' ··· 17 16 import {useSession} from '#/state/session' 18 17 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 19 18 import {useCloseAllActiveElements} from '#/state/util' 19 + import {IS_ANDROID, IS_IOS} from '#/env' 20 20 import {resetToTab} from '#/Navigation' 21 21 import {router} from '#/routes' 22 22 ··· 90 90 // channels allow for the mute/unmute functionality we want for the background 91 91 // handler. 92 92 useEffect(() => { 93 - if (!isAndroid) return 93 + if (!IS_ANDROID) return 94 94 // assign both chat notifications to a group 95 95 // NOTE: I don't think that it will retroactively move them into the group 96 96 // if the channels already exist. no big deal imo -sfn ··· 379 379 } 380 380 381 381 const payload = ( 382 - isIOS ? e.request.trigger.payload : e.request.content.data 382 + IS_IOS ? e.request.trigger.payload : e.request.content.data 383 383 ) as NotificationPayload 384 384 385 385 if (payload && payload.reason) {
+4 -4
src/lib/hooks/useOTAUpdates.ts
··· 12 12 13 13 import {isNetworkError} from '#/lib/strings/errors' 14 14 import {logger} from '#/logger' 15 - import {isAndroid, isIOS} from '#/platform/detection' 15 + import {IS_ANDROID, IS_IOS} from '#/env' 16 16 import {IS_TESTFLIGHT} from '#/env' 17 17 18 18 const MINIMUM_MINIMIZE_TIME = 15 * 60e3 19 19 20 20 async function setExtraParams() { 21 21 await setExtraParamAsync( 22 - isIOS ? 'ios-build-number' : 'android-build-number', 22 + IS_IOS ? 'ios-build-number' : 'android-build-number', 23 23 // Hilariously, `buildVersion` is not actually a string on Android even though the TS type says it is. 24 24 // This just ensures it gets passed as a string 25 25 `${nativeBuildVersion}`, ··· 32 32 33 33 async function setExtraParamsPullRequest(channel: string) { 34 34 await setExtraParamAsync( 35 - isIOS ? 'ios-build-number' : 'android-build-number', 35 + IS_IOS ? 'ios-build-number' : 'android-build-number', 36 36 // Hilariously, `buildVersion` is not actually a string on Android even though the TS type says it is. 37 37 // This just ensures it gets passed as a string 38 38 `${nativeBuildVersion}`, ··· 198 198 // `maintainVisibleContentPosition`. See repro repo for more details: 199 199 // https://github.com/mozzius/ota-crash-repro 200 200 // Old Arch only - re-enable once we're on the New Archictecture! -sfn 201 - if (isAndroid) return 201 + if (IS_ANDROID) return 202 202 203 203 const subscription = AppState.addEventListener( 204 204 'change',
+2 -2
src/lib/hooks/useOpenLink.ts
··· 12 12 toNiceDomain, 13 13 } from '#/lib/strings/url-helpers' 14 14 import {logger} from '#/logger' 15 - import {isNative} from '#/platform/detection' 16 15 import {useInAppBrowser} from '#/state/preferences/in-app-browser' 17 16 import {useTheme} from '#/alf' 18 17 import {useDialogContext} from '#/components/Dialog' 19 18 import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' 19 + import {IS_NATIVE} from '#/env' 20 20 21 21 export function useOpenLink() { 22 22 const enabled = useInAppBrowser() ··· 41 41 } 42 42 } 43 43 44 - if (isNative && !url.startsWith('mailto:')) { 44 + if (IS_NATIVE && !url.startsWith('mailto:')) { 45 45 if (override === undefined && enabled === undefined) { 46 46 // consent dialog is a global dialog, and while it's possible to nest dialogs, 47 47 // the actual components need to be nested. sibling dialogs on iOS are not supported.
+3 -3
src/lib/hooks/usePermissions.ts
··· 2 2 import {useCameraPermissions as useExpoCameraPermissions} from 'expo-camera' 3 3 import * as MediaLibrary from 'expo-media-library' 4 4 5 - import {isWeb} from '#/platform/detection' 6 5 import {Alert} from '#/view/com/util/Alert' 6 + import {IS_WEB} from '#/env' 7 7 8 8 const openPermissionAlert = (perm: string) => { 9 9 Alert.alert( ··· 26 26 const requestPhotoAccessIfNeeded = async () => { 27 27 // On the, we use <input type="file"> to produce a filepicker 28 28 // This does not need any permission granting. 29 - if (isWeb) { 29 + if (IS_WEB) { 30 30 return true 31 31 } 32 32 ··· 55 55 const requestVideoAccessIfNeeded = async () => { 56 56 // On the, we use <input type="file"> to produce a filepicker 57 57 // This does not need any permission granting. 58 - if (isWeb) { 58 + if (IS_WEB) { 59 59 return true 60 60 } 61 61
+2 -2
src/lib/hooks/useTranslate.ts
··· 2 2 import * as IntentLauncher from 'expo-intent-launcher' 3 3 4 4 import {getTranslatorLink} from '#/locale/helpers' 5 - import {isAndroid} from '#/platform/detection' 5 + import {IS_ANDROID} from '#/env' 6 6 import {useOpenLink} from './useOpenLink' 7 7 8 8 export function useTranslate() { ··· 11 11 return useCallback( 12 12 async (text: string, language: string) => { 13 13 const translateUrl = getTranslatorLink(text, language) 14 - if (isAndroid) { 14 + if (IS_ANDROID) { 15 15 try { 16 16 // use getApplicationIconAsync to determine if the translate app is installed 17 17 if (
+2 -2
src/lib/hooks/useWebMediaQueries.tsx
··· 1 1 import {useMediaQuery} from 'react-responsive' 2 2 3 - import {isNative} from '#/platform/detection' 3 + import {IS_NATIVE} from '#/env' 4 4 5 5 /** 6 6 * @deprecated use `useBreakpoints` from `#/alf` instead ··· 11 11 const isMobile = useMediaQuery({maxWidth: 800 - 1}) 12 12 const isTabletOrMobile = isMobile || isTablet 13 13 const isTabletOrDesktop = isDesktop || isTablet 14 - if (isNative) { 14 + if (IS_NATIVE) { 15 15 return { 16 16 isMobile: true, 17 17 isTablet: false,
+4 -4
src/lib/media/manip.ts
··· 18 18 19 19 import {POST_IMG_MAX} from '#/lib/constants' 20 20 import {logger} from '#/logger' 21 - import {isAndroid, isIOS} from '#/platform/detection' 21 + import {IS_ANDROID, IS_IOS} from '#/env' 22 22 import {type PickerImage} from './picker.shared' 23 23 import {type Dimensions} from './types' 24 24 import {mimeToExt} from './video/util' ··· 109 109 110 110 // save 111 111 try { 112 - if (isAndroid) { 112 + if (IS_ANDROID) { 113 113 // android triggers an annoying permission prompt if you try and move an image 114 114 // between albums. therefore, we need to either create the album with the image 115 115 // as the starting image, or put it directly into the album ··· 327 327 } 328 328 329 329 function normalizePath(str: string, allPlatforms = false): string { 330 - if (isAndroid || allPlatforms) { 330 + if (IS_ANDROID || allPlatforms) { 331 331 if (!str.startsWith('file://')) { 332 332 return `file://${str}` 333 333 } ··· 350 350 type: string, 351 351 ) { 352 352 try { 353 - if (isIOS) { 353 + if (IS_IOS) { 354 354 await withTempFile(filename, encoded, async tmpFileUrl => { 355 355 await Sharing.shareAsync(tmpFileUrl, {UTI: type}) 356 356 })
+1 -1
src/lib/media/picker.e2e.tsx
··· 3 3 getInfoAsync, 4 4 readDirectoryAsync, 5 5 } from 'expo-file-system/legacy' 6 + import {type ImagePickerResult} from 'expo-image-picker' 6 7 import ExpoImageCropTool, { 7 8 type OpenCropperOptions, 8 9 } from '@bsky.app/expo-image-crop-tool' 9 10 10 11 import {compressIfNeeded} from './manip' 11 12 import {type PickerImage} from './picker.shared' 12 - import {ImagePickerResult} from 'expo-image-picker' 13 13 14 14 async function getFile() { 15 15 const imagesDir = documentDirectory!
+3 -3
src/lib/media/picker.shared.ts
··· 5 5 } from 'expo-image-picker' 6 6 import {t} from '@lingui/macro' 7 7 8 - import {isIOS, isWeb} from '#/platform/detection' 9 8 import {type ImageMeta} from '#/state/gallery' 10 9 import * as Toast from '#/view/com/util/Toast' 10 + import {IS_IOS, IS_WEB} from '#/env' 11 11 import {VIDEO_MAX_DURATION_MS} from '../constants' 12 12 import {getDataUriSize} from './util' 13 13 ··· 53 53 quality: 1, 54 54 allowsMultipleSelection: true, 55 55 legacy: true, 56 - base64: isWeb, 57 - selectionLimit: isIOS ? selectionCountRemaining : undefined, 56 + base64: IS_WEB, 57 + selectionLimit: IS_IOS ? selectionCountRemaining : undefined, 58 58 preferredAssetRepresentationMode: 59 59 UIImagePickerPreferredAssetRepresentationMode.Automatic, 60 60 videoMaxDuration: VIDEO_MAX_DURATION_MS / 1000,
+2 -2
src/lib/media/save-image.ios.ts
··· 2 2 import {msg} from '@lingui/macro' 3 3 import {useLingui} from '@lingui/react' 4 4 5 - import {isNative} from '#/platform/detection' 6 5 import * as Toast from '#/components/Toast' 6 + import {IS_NATIVE} from '#/env' 7 7 import {saveImageToMediaLibrary} from './manip' 8 8 9 9 /** ··· 16 16 const {_} = useLingui() 17 17 return useCallback( 18 18 async (uri: string) => { 19 - if (!isNative) { 19 + if (!IS_NATIVE) { 20 20 throw new Error('useSaveImageToMediaLibrary is native only') 21 21 } 22 22
+2 -2
src/lib/media/save-image.ts
··· 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {isNative} from '#/platform/detection' 7 6 import * as Toast from '#/components/Toast' 7 + import {IS_NATIVE} from '#/env' 8 8 import {saveImageToMediaLibrary} from './manip' 9 9 10 10 /** ··· 18 18 }) 19 19 return useCallback( 20 20 async (uri: string) => { 21 - if (!isNative) { 21 + if (!IS_NATIVE) { 22 22 throw new Error('useSaveImageToMediaLibrary is native only') 23 23 } 24 24
+5 -5
src/lib/notifications/notifications.ts
··· 13 13 } from '#/lib/constants' 14 14 import {logger as notyLogger} from '#/lib/notifications/util' 15 15 import {isNetworkError} from '#/lib/strings/errors' 16 - import {isNative} from '#/platform/detection' 17 16 import {type SessionAccount, useAgent, useSession} from '#/state/session' 18 17 import BackgroundNotificationHandler from '#/../modules/expo-background-notification-handler' 19 18 import {useAgeAssurance} from '#/ageAssurance' 19 + import {IS_NATIVE} from '#/env' 20 20 import {IS_DEV} from '#/env' 21 21 22 22 /** ··· 140 140 }: { 141 141 isAgeRestricted?: boolean 142 142 } = {}) => { 143 - if (!isNative || IS_DEV) return 143 + if (!IS_NATIVE || IS_DEV) return 144 144 145 145 /** 146 146 * This will also fire the listener added via `addPushTokenListener`. That ··· 236 236 const permissions = await Notifications.getPermissionsAsync() 237 237 238 238 if ( 239 - !isNative || 239 + !IS_NATIVE || 240 240 permissions?.status === 'granted' || 241 241 (permissions?.status === 'denied' && !permissions.canAskAgain) 242 242 ) { ··· 277 277 } 278 278 279 279 export async function decrementBadgeCount(by: number) { 280 - if (!isNative) return 280 + if (!IS_NATIVE) return 281 281 282 282 let count = await getBadgeCountAsync() 283 283 count -= by ··· 295 295 } 296 296 297 297 export async function unregisterPushToken(agents: AtpAgent[]) { 298 - if (!isNative) return 298 + if (!IS_NATIVE) return 299 299 300 300 try { 301 301 const token = await getPushToken()
+3 -3
src/lib/react-query.tsx
··· 9 9 } from '@tanstack/react-query-persist-client' 10 10 import type React from 'react' 11 11 12 - import {isNative, isWeb} from '#/platform/detection' 13 12 import {listenNetworkConfirmed, listenNetworkLost} from '#/state/events' 14 13 import {PUBLIC_BSKY_SERVICE} from './constants' 14 + import {IS_NATIVE, IS_WEB} from '#/env' 15 15 16 16 declare global { 17 17 interface Window { ··· 88 88 }, 2000) 89 89 90 90 focusManager.setEventListener(onFocus => { 91 - if (isNative) { 91 + if (IS_NATIVE) { 92 92 const subscription = AppState.addEventListener( 93 93 'change', 94 94 (status: AppStateStatus) => { ··· 188 188 } 189 189 }) 190 190 useEffect(() => { 191 - if (isWeb) { 191 + if (IS_WEB) { 192 192 window.__TANSTACK_QUERY_CLIENT__ = queryClient 193 193 } 194 194 }, [queryClient])
+4 -4
src/lib/sharing.ts
··· 4 4 // TODO: replace global i18n instance with one returned from useLingui -sfn 5 5 import {t} from '@lingui/macro' 6 6 7 - import {isAndroid, isIOS} from '#/platform/detection' 8 7 import * as Toast from '#/view/com/util/Toast' 8 + import {IS_ANDROID, IS_IOS} from '#/env' 9 9 10 10 /** 11 11 * This function shares a URL using the native Share API if available, or copies it to the clipboard ··· 14 14 * clipboard. 15 15 */ 16 16 export async function shareUrl(url: string) { 17 - if (isAndroid) { 17 + if (IS_ANDROID) { 18 18 await Share.share({message: url}) 19 - } else if (isIOS) { 19 + } else if (IS_IOS) { 20 20 await Share.share({url}) 21 21 } else { 22 22 // React Native Share is not supported by web. Web Share API ··· 34 34 * clipboard. 35 35 */ 36 36 export async function shareText(text: string) { 37 - if (isAndroid || isIOS) { 37 + if (IS_ANDROID || IS_IOS) { 38 38 await Share.share({message: text}) 39 39 } else { 40 40 await setStringAsync(text)
+1 -1
src/lib/statsig/gates.ts
··· 3 3 | 'alt_share_icon' 4 4 | 'debug_show_feedcontext' 5 5 | 'debug_subscriptions' 6 + | 'disable_live_now_beta' 6 7 | 'disable_onboarding_find_contacts' 7 8 | 'disable_settings_find_contacts' 8 9 | 'explore_show_suggested_feeds' 9 10 | 'feed_reply_button_open_thread' 10 11 | 'is_bsky_team_member' // special, do not remove 11 - | 'live_now_beta' 12 12 | 'old_postonboarding' 13 13 | 'onboarding_add_video_feed' 14 14 | 'onboarding_suggested_starterpacks'
+2 -3
src/lib/statsig/statsig.tsx
··· 5 5 6 6 import {logger} from '#/logger' 7 7 import {type MetricEvents} from '#/logger/metrics' 8 - import {isWeb} from '#/platform/detection' 9 8 import * as persisted from '#/state/persisted' 10 - // import {useSession} from '../../state/session' 9 + import {IS_WEB} from '#/env' 11 10 import * as env from '#/env' 12 11 import {device} from '#/storage' 13 12 import {timeout} from '../async/timeout' ··· 38 37 39 38 let refSrc = '' 40 39 let refUrl = '' 41 - if (isWeb && typeof window !== 'undefined') { 40 + if (IS_WEB && typeof window !== 'undefined') { 42 41 const params = new URLSearchParams(window.location.search) 43 42 refSrc = params.get('ref_src') ?? '' 44 43 refUrl = decodeURIComponent(params.get('ref_url') ?? '')
+5 -6
src/lib/strings/embed-player.ts
··· 1 1 import {Dimensions} from 'react-native' 2 2 3 - import {isSafari} from '#/lib/browser' 4 - import {isWeb} from '#/platform/detection' 3 + import {IS_WEB, IS_WEB_SAFARI} from '#/env' 5 4 6 5 const {height: SCREEN_HEIGHT} = Dimensions.get('window') 7 6 8 - const IFRAME_HOST = isWeb 7 + const IFRAME_HOST = IS_WEB 9 8 ? // @ts-ignore only for web 10 9 window.location.host === 'localhost:8100' 11 10 ? 'http://localhost:8100' ··· 135 134 urlp.hostname === 'www.twitch.tv' || 136 135 urlp.hostname === 'm.twitch.tv' 137 136 ) { 138 - const parent = isWeb 137 + const parent = IS_WEB 139 138 ? // @ts-ignore only for web 140 139 window.location.hostname 141 140 : 'localhost' ··· 570 569 width: Number(w), 571 570 } 572 571 573 - if (isWeb) { 574 - if (isSafari) { 572 + if (IS_WEB) { 573 + if (IS_WEB_SAFARI) { 575 574 id = id.replace('AAAAC', 'AAAP1') 576 575 filename = filename.replace('.gif', '.mp4') 577 576 } else {
+2 -2
src/lib/styles.ts
··· 5 5 type TextStyle, 6 6 } from 'react-native' 7 7 8 - import {isWeb} from '#/platform/detection' 8 + import {IS_WEB} from '#/env' 9 9 import {type Theme, type TypographyVariant} from './ThemeContext' 10 10 11 11 // 1 is lightest, 2 is light, 3 is mid, 4 is dark, 5 is darkest ··· 186 186 // dimensions 187 187 w100pct: {width: '100%'}, 188 188 h100pct: {height: '100%'}, 189 - hContentRegion: isWeb ? {minHeight: '100%'} : {height: '100%'}, 189 + hContentRegion: IS_WEB ? {minHeight: '100%'} : {height: '100%'}, 190 190 window: { 191 191 width: Dimensions.get('window').width, 192 192 height: Dimensions.get('window').height,
+139 -139
src/locale/locales/en/messages.po
··· 18 18 msgid "\"{interestsDisplayName}\" category (active)" 19 19 msgstr "" 20 20 21 - #: src/screens/Messages/components/ChatListItem.tsx:163 21 + #: src/screens/Messages/components/ChatListItem.tsx:162 22 22 msgid "(contains embedded content)" 23 23 msgstr "" 24 24 ··· 163 163 msgid "{0} is not available" 164 164 msgstr "" 165 165 166 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:232 166 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:231 167 167 msgid "{0} joined this week" 168 168 msgstr "" 169 169 ··· 180 180 msgid "{0} reacted {1}" 181 181 msgstr "" 182 182 183 - #: src/screens/Messages/components/ChatListItem.tsx:234 183 + #: src/screens/Messages/components/ChatListItem.tsx:233 184 184 msgid "{0} reacted {1} to {2}" 185 185 msgstr "" 186 186 ··· 192 192 msgid "{0}, a list by {1}" 193 193 msgstr "" 194 194 195 - #: src/view/com/util/UserAvatar.tsx:578 196 - #: src/view/com/util/UserAvatar.tsx:596 195 + #: src/view/com/util/UserAvatar.tsx:577 196 + #: src/view/com/util/UserAvatar.tsx:595 197 197 msgid "{0}'s avatar" 198 198 msgstr "" 199 199 ··· 540 540 msgstr "" 541 541 542 542 #. If last message does not contain text, fall back to "{user} reacted to {a message}" 543 - #: src/screens/Messages/components/ChatListItem.tsx:213 543 + #: src/screens/Messages/components/ChatListItem.tsx:212 544 544 msgid "a message" 545 545 msgstr "" 546 546 ··· 714 714 msgid "Add a content warning" 715 715 msgstr "" 716 716 717 - #: src/components/live/GoLiveDialog.tsx:103 717 + #: src/components/live/GoLiveDialog.tsx:106 718 718 msgid "Add a temporary live status to your profile. When someone clicks on your avatar, they’ll see information about your live event." 719 719 msgstr "" 720 720 ··· 738 738 msgid "Add alt text" 739 739 msgstr "" 740 740 741 - #: src/view/com/composer/videos/SubtitleDialog.tsx:110 741 + #: src/view/com/composer/videos/SubtitleDialog.tsx:114 742 742 msgid "Add alt text (optional)" 743 743 msgstr "" 744 744 ··· 826 826 msgid "Add this feed to your feeds" 827 827 msgstr "" 828 828 829 - #: src/view/com/profile/ProfileMenu.tsx:340 830 - #: src/view/com/profile/ProfileMenu.tsx:343 829 + #: src/view/com/profile/ProfileMenu.tsx:342 830 + #: src/view/com/profile/ProfileMenu.tsx:345 831 831 msgid "Add to lists" 832 832 msgstr "" 833 833 ··· 836 836 msgstr "" 837 837 838 838 #: src/components/dialogs/StarterPackDialog.tsx:176 839 - #: src/view/com/profile/ProfileMenu.tsx:331 840 - #: src/view/com/profile/ProfileMenu.tsx:334 839 + #: src/view/com/profile/ProfileMenu.tsx:333 840 + #: src/view/com/profile/ProfileMenu.tsx:336 841 841 msgid "Add to starter packs" 842 842 msgstr "" 843 843 ··· 1022 1022 #: src/view/com/composer/GifAltText.tsx:154 1023 1023 #: src/view/com/composer/photos/ImageAltTextDialog.tsx:117 1024 1024 #: src/view/com/composer/videos/SubtitleDialog.tsx:40 1025 - #: src/view/com/composer/videos/SubtitleDialog.tsx:55 1026 - #: src/view/com/composer/videos/SubtitleDialog.tsx:105 1025 + #: src/view/com/composer/videos/SubtitleDialog.tsx:58 1027 1026 #: src/view/com/composer/videos/SubtitleDialog.tsx:109 1027 + #: src/view/com/composer/videos/SubtitleDialog.tsx:113 1028 1028 msgid "Alt text" 1029 1029 msgstr "" 1030 1030 ··· 1036 1036 msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone." 1037 1037 msgstr "" 1038 1038 1039 - #: src/view/com/composer/videos/SubtitleDialog.tsx:133 1039 + #: src/view/com/composer/videos/SubtitleDialog.tsx:137 1040 1040 msgid "Alt text must be less than {MAX_ALT_TEXT} characters." 1041 1041 msgstr "" 1042 1042 ··· 1054 1054 msgid "An error has occurred" 1055 1055 msgstr "" 1056 1056 1057 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:422 1057 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:421 1058 1058 msgid "An error occurred" 1059 1059 msgstr "" 1060 1060 ··· 1151 1151 msgid "An mockup of a iPhone showing the Bluesky app open to the profile of a verified user with a blue checkmark next to their display name." 1152 1152 msgstr "" 1153 1153 1154 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:166 1154 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:164 1155 1155 msgid "An unknown error occurred." 1156 1156 msgstr "" 1157 1157 ··· 1476 1476 1477 1477 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:818 1478 1478 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:190 1479 - #: src/view/com/profile/ProfileMenu.tsx:548 1479 + #: src/view/com/profile/ProfileMenu.tsx:550 1480 1480 msgid "Block" 1481 1481 msgstr "" 1482 1482 ··· 1486 1486 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:705 1487 1487 #: src/screens/Messages/components/RequestButtons.tsx:144 1488 1488 #: src/screens/Messages/components/RequestButtons.tsx:146 1489 - #: src/view/com/profile/ProfileMenu.tsx:454 1490 - #: src/view/com/profile/ProfileMenu.tsx:461 1489 + #: src/view/com/profile/ProfileMenu.tsx:456 1490 + #: src/view/com/profile/ProfileMenu.tsx:463 1491 1491 msgid "Block account" 1492 1492 msgstr "" 1493 1493 1494 1494 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:813 1495 - #: src/view/com/profile/ProfileMenu.tsx:531 1495 + #: src/view/com/profile/ProfileMenu.tsx:533 1496 1496 msgid "Block Account?" 1497 1497 msgstr "" 1498 1498 ··· 1544 1544 msgstr "" 1545 1545 1546 1546 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:815 1547 - #: src/view/com/profile/ProfileMenu.tsx:543 1547 + #: src/view/com/profile/ProfileMenu.tsx:545 1548 1548 msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." 1549 1549 msgstr "" 1550 1550 ··· 1560 1560 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." 1561 1561 msgstr "" 1562 1562 1563 - #: src/view/com/profile/ProfileMenu.tsx:540 1563 + #: src/view/com/profile/ProfileMenu.tsx:542 1564 1564 msgid "Blocking will not prevent labels from being applied on your account, but it will stop this account from replying in your threads or interacting with you." 1565 1565 msgstr "" 1566 1566 ··· 1761 1761 #: src/components/dialogs/InAppBrowserConsent.tsx:104 1762 1762 #: src/components/dialogs/lists/CreateOrEditListDialog.tsx:274 1763 1763 #: src/components/dialogs/lists/CreateOrEditListDialog.tsx:282 1764 - #: src/components/live/GoLiveDialog.tsx:243 1765 - #: src/components/live/GoLiveDialog.tsx:249 1764 + #: src/components/live/GoLiveDialog.tsx:246 1765 + #: src/components/live/GoLiveDialog.tsx:252 1766 1766 #: src/components/Menu/index.tsx:352 1767 1767 #: src/components/PostControls/RepostButton.tsx:209 1768 1768 #: src/components/Prompt.tsx:144 1769 1769 #: src/components/Prompt.tsx:146 1770 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:153 1771 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:158 1770 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:151 1771 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:156 1772 1772 #: src/lib/media/picker.tsx:38 1773 1773 #: src/screens/Deactivated.tsx:149 1774 1774 #: src/screens/Profile/Header/EditProfileDialog.tsx:218 ··· 1821 1821 msgid "Cannot interact with a blocked user" 1822 1822 msgstr "" 1823 1823 1824 - #: src/view/com/composer/videos/SubtitleDialog.tsx:148 1824 + #: src/view/com/composer/videos/SubtitleDialog.tsx:152 1825 1825 msgid "Captions (.vtt)" 1826 1826 msgstr "" 1827 1827 1828 1828 #: src/view/com/composer/videos/SubtitleDialog.tsx:40 1829 - #: src/view/com/composer/videos/SubtitleDialog.tsx:55 1829 + #: src/view/com/composer/videos/SubtitleDialog.tsx:56 1830 1830 msgid "Captions & alt text" 1831 1831 msgstr "" 1832 1832 ··· 2431 2431 msgid "Conversation deleted" 2432 2432 msgstr "" 2433 2433 2434 - #: src/screens/Messages/components/ChatListItem.tsx:199 2434 + #: src/screens/Messages/components/ChatListItem.tsx:198 2435 2435 msgid "Conversation deleted" 2436 2436 msgstr "" 2437 2437 ··· 2465 2465 msgid "Copy App Password" 2466 2466 msgstr "" 2467 2467 2468 - #: src/view/com/profile/ProfileMenu.tsx:491 2469 - #: src/view/com/profile/ProfileMenu.tsx:494 2468 + #: src/view/com/profile/ProfileMenu.tsx:493 2469 + #: src/view/com/profile/ProfileMenu.tsx:496 2470 2470 msgid "Copy at:// URI" 2471 2471 msgstr "" 2472 2472 ··· 2481 2481 msgstr "" 2482 2482 2483 2483 #: src/screens/Settings/components/ChangeHandleDialog.tsx:502 2484 - #: src/view/com/profile/ProfileMenu.tsx:500 2485 - #: src/view/com/profile/ProfileMenu.tsx:503 2484 + #: src/view/com/profile/ProfileMenu.tsx:502 2485 + #: src/view/com/profile/ProfileMenu.tsx:505 2486 2486 msgid "Copy DID" 2487 2487 msgstr "" 2488 2488 ··· 2495 2495 msgid "Copy link" 2496 2496 msgstr "" 2497 2497 2498 - #: src/components/StarterPack/ShareDialog.tsx:119 2498 + #: src/components/StarterPack/ShareDialog.tsx:120 2499 2499 msgid "Copy Link" 2500 2500 msgstr "" 2501 2501 ··· 2671 2671 msgid "Create an account" 2672 2672 msgstr "" 2673 2673 2674 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:312 2675 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:319 2674 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:311 2675 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:318 2676 2676 msgid "Create an account without using this starter pack" 2677 2677 msgstr "" 2678 2678 ··· 2976 2976 msgid "Disable replies entirely" 2977 2977 msgstr "" 2978 2978 2979 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:388 2979 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:387 2980 2980 msgid "Disable subtitles" 2981 2981 msgstr "" 2982 2982 ··· 3119 3119 #: src/view/com/composer/labels/LabelsBtn.tsx:218 3120 3120 #: src/view/com/composer/labels/LabelsBtn.tsx:225 3121 3121 #: src/view/com/composer/select-language/PostLanguageSelectDialog.tsx:303 3122 - #: src/view/com/composer/videos/SubtitleDialog.tsx:184 3123 - #: src/view/com/composer/videos/SubtitleDialog.tsx:195 3122 + #: src/view/com/composer/videos/SubtitleDialog.tsx:188 3123 + #: src/view/com/composer/videos/SubtitleDialog.tsx:199 3124 3124 msgid "Done" 3125 3125 msgstr "" 3126 3126 ··· 3146 3146 msgid "Double tap to like" 3147 3147 msgstr "" 3148 3148 3149 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:330 3149 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:329 3150 3150 msgid "Download Bluesky" 3151 3151 msgstr "" 3152 3152 ··· 3221 3221 msgid "Edit" 3222 3222 msgstr "" 3223 3223 3224 - #: src/view/com/util/UserAvatar.tsx:440 3224 + #: src/view/com/util/UserAvatar.tsx:439 3225 3225 #: src/view/com/util/UserBanner.tsx:121 3226 3226 msgid "Edit avatar" 3227 3227 msgstr "" ··· 3251 3251 msgid "Edit list details" 3252 3252 msgstr "" 3253 3253 3254 - #: src/view/com/profile/ProfileMenu.tsx:354 3255 - #: src/view/com/profile/ProfileMenu.tsx:374 3254 + #: src/view/com/profile/ProfileMenu.tsx:356 3255 + #: src/view/com/profile/ProfileMenu.tsx:376 3256 3256 msgid "Edit live status" 3257 3257 msgstr "" 3258 3258 ··· 3408 3408 msgid "Enable quote posts of this post" 3409 3409 msgstr "" 3410 3410 3411 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:389 3411 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:388 3412 3412 msgid "Enable subtitles" 3413 3413 msgstr "" 3414 3414 ··· 3436 3436 msgid "End of feed" 3437 3437 msgstr "" 3438 3438 3439 - #: src/view/com/composer/videos/SubtitleDialog.tsx:174 3439 + #: src/view/com/composer/videos/SubtitleDialog.tsx:178 3440 3440 msgid "Ensure you have selected a language for each subtitle file." 3441 3441 msgstr "" 3442 3442 ··· 3459 3459 msgid "Enter code" 3460 3460 msgstr "" 3461 3461 3462 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:407 3462 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:406 3463 3463 msgid "Enter fullscreen" 3464 3464 msgstr "" 3465 3465 ··· 3529 3529 msgid "Error occurred while saving file" 3530 3530 msgstr "" 3531 3531 3532 - #: src/screens/Signup/StepCaptcha/index.tsx:123 3532 + #: src/screens/Signup/StepCaptcha/index.tsx:125 3533 3533 msgid "Error receiving captcha response." 3534 3534 msgstr "" 3535 3535 ··· 3565 3565 msgid "Excludes users you follow" 3566 3566 msgstr "" 3567 3567 3568 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:406 3568 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:405 3569 3569 msgid "Exit fullscreen" 3570 3570 msgstr "" 3571 3571 ··· 4121 4121 msgid "Follow 7 accounts" 4122 4122 msgstr "" 4123 4123 4124 - #: src/view/com/profile/ProfileMenu.tsx:310 4125 - #: src/view/com/profile/ProfileMenu.tsx:321 4124 + #: src/view/com/profile/ProfileMenu.tsx:312 4125 + #: src/view/com/profile/ProfileMenu.tsx:323 4126 4126 msgid "Follow account" 4127 4127 msgstr "" 4128 4128 ··· 4433 4433 msgid "Go Home" 4434 4434 msgstr "" 4435 4435 4436 - #: src/view/com/profile/ProfileMenu.tsx:355 4437 - #: src/view/com/profile/ProfileMenu.tsx:376 4436 + #: src/view/com/profile/ProfileMenu.tsx:357 4437 + #: src/view/com/profile/ProfileMenu.tsx:378 4438 4438 msgid "Go live" 4439 4439 msgstr "" 4440 4440 4441 - #: src/components/live/GoLiveDialog.tsx:95 4442 - #: src/components/live/GoLiveDialog.tsx:100 4443 - #: src/components/live/GoLiveDialog.tsx:228 4444 - #: src/components/live/GoLiveDialog.tsx:237 4441 + #: src/components/live/GoLiveDialog.tsx:98 4442 + #: src/components/live/GoLiveDialog.tsx:103 4443 + #: src/components/live/GoLiveDialog.tsx:231 4444 + #: src/components/live/GoLiveDialog.tsx:240 4445 4445 msgid "Go Live" 4446 4446 msgstr "" 4447 4447 4448 - #: src/view/com/profile/ProfileMenu.tsx:352 4449 - #: src/view/com/profile/ProfileMenu.tsx:372 4448 + #: src/view/com/profile/ProfileMenu.tsx:354 4449 + #: src/view/com/profile/ProfileMenu.tsx:374 4450 4450 msgid "Go live (disabled)" 4451 4451 msgstr "" 4452 4452 4453 - #: src/components/live/GoLiveDialog.tsx:170 4453 + #: src/components/live/GoLiveDialog.tsx:173 4454 4454 msgid "Go live for" 4455 4455 msgstr "" 4456 4456 ··· 4465 4465 msgid "Go to account settings" 4466 4466 msgstr "" 4467 4467 4468 - #: src/screens/Messages/components/ChatListItem.tsx:364 4468 + #: src/screens/Messages/components/ChatListItem.tsx:363 4469 4469 msgid "Go to conversation with {0}" 4470 4470 msgstr "" 4471 4471 ··· 4644 4644 msgid "Hide" 4645 4645 msgstr "" 4646 4646 4647 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:140 4648 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:147 4647 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:138 4648 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:145 4649 4649 msgid "Hide all events" 4650 4650 msgstr "" 4651 4651 ··· 4676 4676 msgid "Hide this card" 4677 4677 msgstr "" 4678 4678 4679 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:128 4680 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:135 4679 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:126 4680 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:133 4681 4681 msgid "Hide this event" 4682 4682 msgstr "" 4683 4683 ··· 4830 4830 msgid "If you believe your birthdate is incorrect, you can update it by <0>clicking here</0>." 4831 4831 msgstr "" 4832 4832 4833 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:119 4833 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:117 4834 4834 msgid "If you choose to hide all events, you can always re-enable them from <0>Settings → Content & Media</0>." 4835 4835 msgstr "" 4836 4836 ··· 5093 5093 msgid "Jobs" 5094 5094 msgstr "" 5095 5095 5096 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:210 5097 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:216 5096 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:209 5097 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:215 5098 5098 #: src/screens/StarterPack/StarterPackScreen.tsx:464 5099 5099 #: src/screens/StarterPack/StarterPackScreen.tsx:475 5100 5100 msgid "Join Bluesky" ··· 5491 5491 msgid "Live event happening now: {0}" 5492 5492 msgstr "" 5493 5493 5494 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:107 5494 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:105 5495 5495 msgid "Live event options" 5496 5496 msgstr "" 5497 5497 5498 - #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:111 5498 + #: src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx:109 5499 5499 msgid "Live events appear occasionally when something exciting is happening. If you'd like, you can hide this particular event, or all events for this placement in your app interface." 5500 5500 msgstr "" 5501 5501 ··· 5505 5505 5506 5506 #: src/components/live/EditLiveDialog.tsx:147 5507 5507 #: src/components/live/EditLiveDialog.tsx:151 5508 - #: src/components/live/GoLiveDialog.tsx:126 5509 - #: src/components/live/GoLiveDialog.tsx:130 5508 + #: src/components/live/GoLiveDialog.tsx:129 5509 + #: src/components/live/GoLiveDialog.tsx:133 5510 5510 msgid "Live link" 5511 5511 msgstr "" 5512 5512 ··· 5665 5665 msgid "Message deleted" 5666 5666 msgstr "" 5667 5667 5668 - #: src/screens/Messages/components/ChatListItem.tsx:200 5668 + #: src/screens/Messages/components/ChatListItem.tsx:199 5669 5669 msgid "Message deleted" 5670 5670 msgstr "" 5671 5671 ··· 5805 5805 msgstr "" 5806 5806 5807 5807 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:153 5808 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:95 5808 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:97 5809 5809 msgctxt "video" 5810 5810 msgid "Mute" 5811 5811 msgstr "" ··· 5817 5817 5818 5818 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:686 5819 5819 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:692 5820 - #: src/view/com/profile/ProfileMenu.tsx:433 5821 - #: src/view/com/profile/ProfileMenu.tsx:440 5820 + #: src/view/com/profile/ProfileMenu.tsx:435 5821 + #: src/view/com/profile/ProfileMenu.tsx:442 5822 5822 msgid "Mute account" 5823 5823 msgstr "" 5824 5824 ··· 5948 5948 msgstr "" 5949 5949 5950 5950 #: src/screens/Search/modules/ExploreTrendingTopics.tsx:196 5951 - #: src/view/com/profile/ProfileMenu.tsx:388 5951 + #: src/view/com/profile/ProfileMenu.tsx:390 5952 5952 msgid "New" 5953 5953 msgstr "" 5954 5954 ··· 6149 6149 msgid "No media yet" 6150 6150 msgstr "" 6151 6151 6152 - #: src/screens/Messages/components/ChatListItem.tsx:142 6152 + #: src/screens/Messages/components/ChatListItem.tsx:141 6153 6153 msgid "No messages yet" 6154 6154 msgstr "" 6155 6155 ··· 6293 6293 msgid "Not Found" 6294 6294 msgstr "" 6295 6295 6296 - #: src/view/com/profile/ProfileMenu.tsx:555 6296 + #: src/view/com/profile/ProfileMenu.tsx:557 6297 6297 msgid "Note about sharing" 6298 6298 msgstr "" 6299 6299 ··· 6475 6475 msgid "Open camera" 6476 6476 msgstr "" 6477 6477 6478 - #: src/screens/Messages/components/ChatListItem.tsx:374 6479 - #: src/screens/Messages/components/ChatListItem.tsx:378 6478 + #: src/screens/Messages/components/ChatListItem.tsx:373 6479 + #: src/screens/Messages/components/ChatListItem.tsx:377 6480 6480 msgid "Open conversation options" 6481 6481 msgstr "" 6482 6482 ··· 6623 6623 msgid "Opens link {0}" 6624 6624 msgstr "" 6625 6625 6626 - #: src/view/com/util/UserAvatar.tsx:582 6626 + #: src/view/com/util/UserAvatar.tsx:581 6627 6627 msgid "Opens live status dialog" 6628 6628 msgstr "" 6629 6629 ··· 6640 6640 msgstr "" 6641 6641 6642 6642 #: src/view/com/notifications/NotificationFeedItem.tsx:1027 6643 - #: src/view/com/util/UserAvatar.tsx:600 6643 + #: src/view/com/util/UserAvatar.tsx:599 6644 6644 msgid "Opens this profile" 6645 6645 msgstr "" 6646 6646 ··· 6760 6760 6761 6761 #: src/components/Post/Embed/ExternalEmbed/Gif.tsx:44 6762 6762 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:137 6763 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:369 6763 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:368 6764 6764 msgid "Pause" 6765 6765 msgstr "" 6766 6766 6767 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:320 6767 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:319 6768 6768 msgid "Pause video" 6769 6769 msgstr "" 6770 6770 ··· 6871 6871 6872 6872 #: src/components/Post/Embed/ExternalEmbed/Gif.tsx:44 6873 6873 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:137 6874 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:370 6874 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:369 6875 6875 msgid "Play" 6876 6876 msgstr "" 6877 6877 ··· 6880 6880 msgstr "" 6881 6881 6882 6882 #: src/components/Post/Embed/VideoEmbed/index.tsx:115 6883 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:321 6883 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:320 6884 6884 msgid "Play video" 6885 6885 msgstr "" 6886 6886 ··· 7065 7065 msgid "Porn" 7066 7066 msgstr "" 7067 7067 7068 - #: src/screens/PostThread/index.tsx:532 7068 + #: src/screens/PostThread/index.tsx:531 7069 7069 msgctxt "description" 7070 7070 msgid "Post" 7071 7071 msgstr "" ··· 7536 7536 msgid "Remove attachment" 7537 7537 msgstr "" 7538 7538 7539 - #: src/view/com/util/UserAvatar.tsx:499 7540 - #: src/view/com/util/UserAvatar.tsx:502 7539 + #: src/view/com/util/UserAvatar.tsx:498 7540 + #: src/view/com/util/UserAvatar.tsx:501 7541 7541 msgid "Remove Avatar" 7542 7542 msgstr "" 7543 7543 ··· 7608 7608 msgid "Remove repost" 7609 7609 msgstr "" 7610 7610 7611 - #: src/view/com/composer/videos/SubtitleDialog.tsx:278 7611 + #: src/view/com/composer/videos/SubtitleDialog.tsx:282 7612 7612 msgid "Remove subtitle file" 7613 7613 msgstr "" 7614 7614 ··· 7627 7627 7628 7628 #: src/components/verification/VerificationRemovePrompt.tsx:46 7629 7629 #: src/components/verification/VerificationsDialog.tsx:252 7630 - #: src/view/com/profile/ProfileMenu.tsx:406 7631 - #: src/view/com/profile/ProfileMenu.tsx:409 7630 + #: src/view/com/profile/ProfileMenu.tsx:408 7631 + #: src/view/com/profile/ProfileMenu.tsx:411 7632 7632 msgid "Remove verification" 7633 7633 msgstr "" 7634 7634 ··· 7763 7763 msgid "Report" 7764 7764 msgstr "" 7765 7765 7766 - #: src/view/com/profile/ProfileMenu.tsx:473 7767 - #: src/view/com/profile/ProfileMenu.tsx:476 7766 + #: src/view/com/profile/ProfileMenu.tsx:475 7767 + #: src/view/com/profile/ProfileMenu.tsx:478 7768 7768 msgid "Report account" 7769 7769 msgstr "" 7770 7770 ··· 8074 8074 msgid "Save changes" 8075 8075 msgstr "" 8076 8076 8077 - #: src/components/StarterPack/ShareDialog.tsx:138 8078 - #: src/components/StarterPack/ShareDialog.tsx:144 8077 + #: src/components/StarterPack/ShareDialog.tsx:142 8078 + #: src/components/StarterPack/ShareDialog.tsx:148 8079 8079 msgid "Save image" 8080 8080 msgstr "" 8081 8081 ··· 8223 8223 msgid "Search my posts" 8224 8224 msgstr "" 8225 8225 8226 - #: src/view/com/profile/ProfileMenu.tsx:289 8227 - #: src/view/com/profile/ProfileMenu.tsx:292 8226 + #: src/view/com/profile/ProfileMenu.tsx:291 8227 + #: src/view/com/profile/ProfileMenu.tsx:294 8228 8228 msgid "Search posts" 8229 8229 msgstr "" 8230 8230 ··· 8350 8350 msgid "Select content languages" 8351 8351 msgstr "" 8352 8352 8353 - #: src/components/live/GoLiveDialog.tsx:175 8353 + #: src/components/live/GoLiveDialog.tsx:178 8354 8354 msgid "Select duration" 8355 8355 msgstr "" 8356 8356 ··· 8384 8384 msgid "Select language" 8385 8385 msgstr "" 8386 8386 8387 - #: src/view/com/composer/videos/SubtitleDialog.tsx:265 8387 + #: src/view/com/composer/videos/SubtitleDialog.tsx:269 8388 8388 msgid "Select language..." 8389 8389 msgstr "" 8390 8390 ··· 8642 8642 msgid "Share a fun fact!" 8643 8643 msgstr "" 8644 8644 8645 - #: src/view/com/profile/ProfileMenu.tsx:560 8645 + #: src/view/com/profile/ProfileMenu.tsx:562 8646 8646 msgid "Share anyway" 8647 8647 msgstr "" 8648 8648 ··· 8654 8654 #: src/components/dialogs/LinkWarning.tsx:96 8655 8655 #: src/components/dialogs/LinkWarning.tsx:104 8656 8656 #: src/components/StarterPack/ShareDialog.tsx:113 8657 - #: src/components/StarterPack/ShareDialog.tsx:119 8657 + #: src/components/StarterPack/ShareDialog.tsx:122 8658 8658 msgid "Share link" 8659 8659 msgstr "" 8660 8660 ··· 8667 8667 msgid "Share post at:// URI" 8668 8668 msgstr "" 8669 8669 8670 - #: src/components/StarterPack/ShareDialog.tsx:123 8671 - #: src/components/StarterPack/ShareDialog.tsx:133 8670 + #: src/components/StarterPack/ShareDialog.tsx:127 8671 + #: src/components/StarterPack/ShareDialog.tsx:137 8672 8672 msgid "Share QR code" 8673 8673 msgstr "" 8674 8674 ··· 8974 8974 msgid "Someone reacted {0}" 8975 8975 msgstr "" 8976 8976 8977 - #: src/screens/Messages/components/ChatListItem.tsx:244 8977 + #: src/screens/Messages/components/ChatListItem.tsx:243 8978 8978 msgid "Someone reacted {0} to {1}" 8979 8979 msgstr "" 8980 8980 ··· 9404 9404 9405 9405 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:186 9406 9406 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:391 9407 - #: src/view/com/profile/ProfileMenu.tsx:536 9407 + #: src/view/com/profile/ProfileMenu.tsx:538 9408 9408 msgid "The account will be able to interact with you after unblocking." 9409 9409 msgstr "" 9410 9410 ··· 9442 9442 msgid "The Discover feed now knows what you like" 9443 9443 msgstr "" 9444 9444 9445 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:333 9445 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:332 9446 9446 msgid "The experience is better in the app. Download Bluesky now and we'll pick back up where you left off." 9447 9447 msgstr "" 9448 9448 ··· 9458 9458 msgid "The following labels were applied to your content." 9459 9459 msgstr "" 9460 9460 9461 - #: src/components/live/GoLiveDialog.tsx:157 9461 + #: src/components/live/GoLiveDialog.tsx:160 9462 9462 msgid "The following services are enabled for your account: {allowedServices}" 9463 9463 msgstr "" 9464 9464 ··· 9551 9551 msgstr "" 9552 9552 9553 9553 #: src/screens/Search/Explore.tsx:999 9554 - #: src/view/com/posts/PostFeed.tsx:759 9554 + #: src/view/com/posts/PostFeed.tsx:758 9555 9555 msgid "There was an issue fetching posts. Tap here to try again." 9556 9556 msgstr "" 9557 9557 ··· 9702 9702 msgid "This content is not viewable without a Bluesky account." 9703 9703 msgstr "" 9704 9704 9705 - #: src/screens/Messages/components/ChatListItem.tsx:366 9705 + #: src/screens/Messages/components/ChatListItem.tsx:365 9706 9706 msgid "This conversation is with a deleted or a deactivated account. Press for options" 9707 9707 msgstr "" 9708 9708 ··· 9757 9757 msgstr "" 9758 9758 9759 9759 #: src/components/live/EditLiveDialog.tsx:176 9760 - #: src/components/live/GoLiveDialog.tsx:150 9760 + #: src/components/live/GoLiveDialog.tsx:153 9761 9761 msgid "This is not a valid link" 9762 9762 msgstr "" 9763 9763 ··· 9817 9817 msgid "This post's author has disabled quote posts." 9818 9818 msgstr "" 9819 9819 9820 - #: src/view/com/profile/ProfileMenu.tsx:557 9820 + #: src/view/com/profile/ProfileMenu.tsx:559 9821 9821 msgid "This profile is only visible to logged-in users. It won't be visible to people who aren't signed in." 9822 9822 msgstr "" 9823 9823 ··· 10090 10090 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:394 10091 10091 #: src/screens/ProfileList/components/Header.tsx:171 10092 10092 #: src/screens/ProfileList/components/Header.tsx:178 10093 - #: src/view/com/profile/ProfileMenu.tsx:548 10093 + #: src/view/com/profile/ProfileMenu.tsx:550 10094 10094 msgid "Unblock" 10095 10095 msgstr "" 10096 10096 ··· 10101 10101 10102 10102 #: src/components/dms/ConvoMenu.tsx:261 10103 10103 #: src/components/dms/ConvoMenu.tsx:264 10104 - #: src/view/com/profile/ProfileMenu.tsx:453 10105 - #: src/view/com/profile/ProfileMenu.tsx:459 10104 + #: src/view/com/profile/ProfileMenu.tsx:455 10105 + #: src/view/com/profile/ProfileMenu.tsx:461 10106 10106 msgid "Unblock account" 10107 10107 msgstr "" 10108 10108 10109 10109 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:184 10110 10110 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:389 10111 - #: src/view/com/profile/ProfileMenu.tsx:530 10111 + #: src/view/com/profile/ProfileMenu.tsx:532 10112 10112 msgid "Unblock Account?" 10113 10113 msgstr "" 10114 10114 ··· 10141 10141 msgid "Unfollow {0}" 10142 10142 msgstr "" 10143 10143 10144 - #: src/view/com/profile/ProfileMenu.tsx:309 10145 - #: src/view/com/profile/ProfileMenu.tsx:319 10144 + #: src/view/com/profile/ProfileMenu.tsx:311 10145 + #: src/view/com/profile/ProfileMenu.tsx:321 10146 10146 msgid "Unfollow account" 10147 10147 msgstr "" 10148 10148 ··· 10184 10184 msgstr "" 10185 10185 10186 10186 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:152 10187 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:94 10187 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:96 10188 10188 msgctxt "video" 10189 10189 msgid "Unmute" 10190 10190 msgstr "" ··· 10201 10201 10202 10202 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:685 10203 10203 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:691 10204 - #: src/view/com/profile/ProfileMenu.tsx:432 10205 - #: src/view/com/profile/ProfileMenu.tsx:438 10204 + #: src/view/com/profile/ProfileMenu.tsx:434 10205 + #: src/view/com/profile/ProfileMenu.tsx:440 10206 10206 msgid "Unmute account" 10207 10207 msgstr "" 10208 10208 ··· 10220 10220 msgid "Unmute thread" 10221 10221 msgstr "" 10222 10222 10223 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:318 10223 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:317 10224 10224 msgid "Unmute video" 10225 10225 msgstr "" 10226 10226 ··· 10339 10339 msgid "Upload a text file to:" 10340 10340 msgstr "" 10341 10341 10342 - #: src/view/com/util/UserAvatar.tsx:470 10343 - #: src/view/com/util/UserAvatar.tsx:473 10342 + #: src/view/com/util/UserAvatar.tsx:469 10343 + #: src/view/com/util/UserAvatar.tsx:472 10344 10344 #: src/view/com/util/UserBanner.tsx:159 10345 10345 #: src/view/com/util/UserBanner.tsx:162 10346 10346 msgid "Upload from Camera" 10347 10347 msgstr "" 10348 10348 10349 - #: src/view/com/util/UserAvatar.tsx:487 10349 + #: src/view/com/util/UserAvatar.tsx:486 10350 10350 #: src/view/com/util/UserBanner.tsx:176 10351 10351 msgid "Upload from Files" 10352 10352 msgstr "" 10353 10353 10354 - #: src/view/com/util/UserAvatar.tsx:481 10355 - #: src/view/com/util/UserAvatar.tsx:485 10354 + #: src/view/com/util/UserAvatar.tsx:480 10355 + #: src/view/com/util/UserAvatar.tsx:484 10356 10356 #: src/view/com/util/UserBanner.tsx:170 10357 10357 #: src/view/com/util/UserBanner.tsx:174 10358 10358 msgid "Upload from Library" ··· 10510 10510 10511 10511 #: src/components/verification/VerificationCreatePrompt.tsx:84 10512 10512 #: src/components/verification/VerificationCreatePrompt.tsx:86 10513 - #: src/view/com/profile/ProfileMenu.tsx:416 10514 - #: src/view/com/profile/ProfileMenu.tsx:419 10513 + #: src/view/com/profile/ProfileMenu.tsx:418 10514 + #: src/view/com/profile/ProfileMenu.tsx:421 10515 10515 msgid "Verify account" 10516 10516 msgstr "" 10517 10517 ··· 10626 10626 msgid "Video not found." 10627 10627 msgstr "" 10628 10628 10629 - #: src/view/com/composer/videos/SubtitleDialog.tsx:102 10629 + #: src/view/com/composer/videos/SubtitleDialog.tsx:106 10630 10630 msgid "Video settings" 10631 10631 msgstr "" 10632 10632 ··· 11120 11120 msgstr "" 11121 11121 11122 11122 #: src/components/live/EditLiveDialog.tsx:152 11123 - #: src/components/live/GoLiveDialog.tsx:131 11123 + #: src/components/live/GoLiveDialog.tsx:134 11124 11124 msgid "www.mylivestream.tv" 11125 11125 msgstr "" 11126 11126 ··· 11464 11464 msgid "You reacted {0}" 11465 11465 msgstr "" 11466 11466 11467 - #: src/screens/Messages/components/ChatListItem.tsx:221 11467 + #: src/screens/Messages/components/ChatListItem.tsx:220 11468 11468 msgid "You reacted {0} to {1}" 11469 11469 msgstr "" 11470 11470 ··· 11494 11494 msgid "You will receive an email with a \"reset code.\" Enter that code here, then enter your new password." 11495 11495 msgstr "" 11496 11496 11497 - #: src/screens/Messages/components/ChatListItem.tsx:157 11497 + #: src/screens/Messages/components/ChatListItem.tsx:156 11498 11498 msgid "You: {0}" 11499 11499 msgstr "" 11500 11500 11501 - #: src/screens/Messages/components/ChatListItem.tsx:186 11501 + #: src/screens/Messages/components/ChatListItem.tsx:185 11502 11502 msgid "You: {defaultEmbeddedContentMessage}" 11503 11503 msgstr "" 11504 11504 11505 - #: src/screens/Messages/components/ChatListItem.tsx:179 11505 + #: src/screens/Messages/components/ChatListItem.tsx:178 11506 11506 msgid "You: {short}" 11507 11507 msgstr "" 11508 11508 ··· 11514 11514 msgid "You'll follow the suggested users once you finish creating your account!" 11515 11515 msgstr "" 11516 11516 11517 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:245 11517 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:244 11518 11518 msgid "You'll follow these people and {0} others" 11519 11519 msgstr "" 11520 11520 11521 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:243 11521 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:242 11522 11522 msgid "You'll follow these people right away" 11523 11523 msgstr "" 11524 11524 ··· 11530 11530 msgid "You'll start receiving notifications for {0}!" 11531 11531 msgstr "" 11532 11532 11533 - #: src/screens/StarterPack/StarterPackLandingScreen.tsx:283 11533 + #: src/screens/StarterPack/StarterPackLandingScreen.tsx:282 11534 11534 msgid "You'll stay updated with these feeds" 11535 11535 msgstr "" 11536 11536
+2 -2
src/logger/index.ts
··· 11 11 type Transport, 12 12 } from '#/logger/types' 13 13 import {enabledLogLevels} from '#/logger/util' 14 - import {isNative} from '#/platform/detection' 14 + import {IS_NATIVE} from '#/env' 15 15 import {ENV} from '#/env' 16 16 import {bitdriftTransport} from './transports/bitdrift' 17 17 import {sentryTransport} from './transports/sentry' ··· 21 21 const TRANSPORTS: Transport[] = (function configureTransports() { 22 22 switch (ENV) { 23 23 case 'production': { 24 - return [sentryTransport, isNative && bitdriftTransport].filter( 24 + return [sentryTransport, IS_NATIVE && bitdriftTransport].filter( 25 25 Boolean, 26 26 ) as Transport[] 27 27 }
+2 -2
src/logger/transports/console.ts
··· 2 2 3 3 import {LogLevel, type Transport} from '#/logger/types' 4 4 import {prepareMetadata} from '#/logger/util' 5 - import {isWeb} from '#/platform/detection' 5 + import {IS_WEB} from '#/env' 6 6 7 7 /** 8 8 * Used in dev mode to nicely log to the console ··· 33 33 msg += ` ${message.toString()}` 34 34 } 35 35 36 - if (isWeb) { 36 + if (IS_WEB) { 37 37 if (hasMetadata) { 38 38 console.groupCollapsed(msg) 39 39 console.log(metadata)
-12
src/platform/detection.ts
··· 1 - import {Platform} from 'react-native' 2 - 3 - export const isIOS = Platform.OS === 'ios' 4 - export const isAndroid = Platform.OS === 'android' 5 - export const isNative = isIOS || isAndroid 6 - export const isWeb = !isNative 7 - export const isMobileWebMediaQuery = 'only screen and (max-width: 1300px)' 8 - export const isMobileWeb = 9 - isWeb && 10 - // @ts-ignore we know window exists -prf 11 - global.window.matchMedia(isMobileWebMediaQuery)?.matches 12 - export const isIPhoneWeb = isWeb && /iPhone/.test(navigator.userAgent)
-26
src/platform/urls.tsx
··· 1 - import {Linking} from 'react-native' 2 - 3 - import {isNative, isWeb} from './detection' 4 - 5 - export async function getInitialURL(): Promise<string | undefined> { 6 - if (isNative) { 7 - const url = await Linking.getInitialURL() 8 - if (url) { 9 - return url 10 - } 11 - return undefined 12 - } else { 13 - // @ts-ignore window exists -prf 14 - if (window.location.pathname !== '/') { 15 - return window.location.pathname 16 - } 17 - return undefined 18 - } 19 - } 20 - 21 - export function clearHash() { 22 - if (isWeb) { 23 - // @ts-ignore window exists -prf 24 - window.location.hash = '' 25 - } 26 - }
+2 -2
src/screens/Bookmarks/index.tsx
··· 21 21 type NativeStackScreenProps, 22 22 } from '#/lib/routes/types' 23 23 import {logger} from '#/logger' 24 - import {isIOS} from '#/platform/detection' 25 24 import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation' 26 25 import {useBookmarksQuery} from '#/state/queries/bookmarks/useBookmarksQuery' 27 26 import {useSetMinimalShellMode} from '#/state/shell' ··· 38 37 import * as Skele from '#/components/Skeleton' 39 38 import * as toast from '#/components/Toast' 40 39 import {Text} from '#/components/Typography' 40 + import {IS_IOS} from '#/env' 41 41 42 42 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Bookmarks'> 43 43 ··· 193 193 } 194 194 initialNumToRender={initialNumToRender} 195 195 windowSize={9} 196 - maxToRenderPerBatch={isIOS ? 5 : 1} 196 + maxToRenderPerBatch={IS_IOS ? 5 : 1} 197 197 updateCellsBatchingPeriod={40} 198 198 sideBorders={false} 199 199 />
+4 -4
src/screens/Deactivated.tsx
··· 7 7 8 8 import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher' 9 9 import {logger} from '#/logger' 10 - import {isWeb} from '#/platform/detection' 11 10 import { 12 11 type SessionAccount, 13 12 useAgent, ··· 25 24 import * as Layout from '#/components/Layout' 26 25 import {Loader} from '#/components/Loader' 27 26 import {Text} from '#/components/Typography' 27 + import {IS_WEB} from '#/env' 28 28 29 29 const COL_WIDTH = 400 30 30 ··· 56 56 }, [setShowLoggedOut]) 57 57 58 58 const onPressLogout = React.useCallback(() => { 59 - if (isWeb) { 59 + if (IS_WEB) { 60 60 // We're switching accounts, which remounts the entire app. 61 61 // On mobile, this gets us Home, but on the web we also need reset the URL. 62 62 // We can't change the URL via a navigate() call because the navigator ··· 102 102 contentContainerStyle={[ 103 103 a.px_2xl, 104 104 { 105 - paddingTop: isWeb ? 64 : insets.top + 16, 106 - paddingBottom: isWeb ? 64 : insets.bottom, 105 + paddingTop: IS_WEB ? 64 : insets.top + 16, 106 + paddingBottom: IS_WEB ? 64 : insets.bottom, 107 107 }, 108 108 ]}> 109 109 <View
+2 -2
src/screens/FindContactsFlowScreen.tsx
··· 9 9 type AllNavigatorParams, 10 10 type NativeStackScreenProps, 11 11 } from '#/lib/routes/types' 12 - import {isNative} from '#/platform/detection' 13 12 import {useSetMinimalShellMode} from '#/state/shell' 14 13 import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' 15 14 import {FindContactsFlow} from '#/components/contacts/FindContactsFlow' 16 15 import {useFindContactsFlowState} from '#/components/contacts/state' 17 16 import * as Layout from '#/components/Layout' 18 17 import {ScreenTransition} from '#/components/ScreenTransition' 18 + import {IS_NATIVE} from '#/env' 19 19 20 20 type Props = NativeStackScreenProps<AllNavigatorParams, 'FindContactsFlow'> 21 21 export function FindContactsFlowScreen({navigation}: Props) { ··· 48 48 49 49 return ( 50 50 <Layout.Screen> 51 - {isNative ? ( 51 + {IS_NATIVE ? ( 52 52 <LayoutAnimationConfig skipEntering skipExiting> 53 53 <ScreenTransition key={state.step} direction={transitionDirection}> 54 54 <FindContactsFlow
+2 -2
src/screens/Login/LoginForm.tsx
··· 18 18 import {cleanError} from '#/lib/strings/errors' 19 19 import {createFullHandle} from '#/lib/strings/handles' 20 20 import {logger} from '#/logger' 21 - import {isIOS} from '#/platform/detection' 22 21 import {useSetHasCheckedForStarterPack} from '#/state/preferences/used-starter-packs' 23 22 import {useSessionApi} from '#/state/session' 24 23 import {useLoggedOutViewControls} from '#/state/shell/logged-out' ··· 32 31 import {Ticket_Stroke2_Corner0_Rounded as Ticket} from '#/components/icons/Ticket' 33 32 import {Loader} from '#/components/Loader' 34 33 import {Text} from '#/components/Typography' 34 + import {IS_IOS} from '#/env' 35 35 import {FormContainer} from './FormContainer' 36 36 37 37 type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema ··· 217 217 inputRef={identifierRef} 218 218 label={_(msg`Username or email address`)} 219 219 autoCapitalize="none" 220 - autoFocus={!isIOS} 220 + autoFocus={!IS_IOS} 221 221 autoCorrect={false} 222 222 autoComplete="username" 223 223 returnKeyType="next"
+3 -3
src/screens/Messages/ChatList.tsx
··· 13 13 import {type MessagesTabNavigatorParams} from '#/lib/routes/types' 14 14 import {cleanError} from '#/lib/strings/errors' 15 15 import {logger} from '#/logger' 16 - import {isNative} from '#/platform/detection' 17 16 import {listenSoftReset} from '#/state/events' 18 17 import {MESSAGE_SCREEN_POLL_INTERVAL} from '#/state/messages/convo/const' 19 18 import {useMessagesEventBus} from '#/state/messages/events' ··· 39 38 import {Link} from '#/components/Link' 40 39 import {ListFooter} from '#/components/Lists' 41 40 import {Text} from '#/components/Typography' 41 + import {IS_NATIVE} from '#/env' 42 42 import {ChatListItem} from './components/ChatListItem' 43 43 import {InboxPreview} from './components/InboxPreview' 44 44 ··· 223 223 224 224 const onSoftReset = useCallback(async () => { 225 225 scrollElRef.current?.scrollToOffset({ 226 - animated: isNative, 226 + animated: IS_NATIVE, 227 227 offset: 0, 228 228 }) 229 229 try { ··· 349 349 hasNextPage={hasNextPage} 350 350 /> 351 351 } 352 - onEndReachedThreshold={isNative ? 1.5 : 0} 352 + onEndReachedThreshold={IS_NATIVE ? 1.5 : 0} 353 353 initialNumToRender={initialNumToRender} 354 354 windowSize={11} 355 355 desktopFixedHeight
+2 -2
src/screens/Messages/Conversation.tsx
··· 21 21 type CommonNavigatorParams, 22 22 type NavigationProp, 23 23 } from '#/lib/routes/types' 24 - import {isWeb} from '#/platform/detection' 25 24 import {type Shadow, useMaybeProfileShadow} from '#/state/cache/profile-shadow' 26 25 import {useEmail} from '#/state/email-verification' 27 26 import {ConvoProvider, isConvoActive, useConvo} from '#/state/messages/convo' ··· 43 42 import {Error} from '#/components/Error' 44 43 import * as Layout from '#/components/Layout' 45 44 import {Loader} from '#/components/Loader' 45 + import {IS_WEB} from '#/env' 46 46 47 47 type Props = NativeStackScreenProps< 48 48 CommonNavigatorParams, ··· 74 74 useCallback(() => { 75 75 setCurrentConvoId(convoId) 76 76 77 - if (isWeb && !gtMobile) { 77 + if (IS_WEB && !gtMobile) { 78 78 setMinimalShellMode(true) 79 79 } else { 80 80 setMinimalShellMode(false)
+2 -2
src/screens/Messages/Inbox.tsx
··· 21 21 } from '#/lib/routes/types' 22 22 import {cleanError} from '#/lib/strings/errors' 23 23 import {logger} from '#/logger' 24 - import {isNative} from '#/platform/detection' 25 24 import {MESSAGE_SCREEN_POLL_INTERVAL} from '#/state/messages/convo/const' 26 25 import {useMessagesEventBus} from '#/state/messages/events' 27 26 import {useLeftConvos} from '#/state/queries/messages/leave-conversation' ··· 44 43 import * as Layout from '#/components/Layout' 45 44 import {ListFooter} from '#/components/Lists' 46 45 import {Text} from '#/components/Typography' 46 + import {IS_NATIVE} from '#/env' 47 47 import {RequestListItem} from './components/RequestListItem' 48 48 49 49 type Props = NativeStackScreenProps<CommonNavigatorParams, 'MessagesInbox'> ··· 288 288 hasNextPage={hasNextPage} 289 289 /> 290 290 } 291 - onEndReachedThreshold={isNative ? 1.5 : 0} 291 + onEndReachedThreshold={IS_NATIVE ? 1.5 : 0} 292 292 initialNumToRender={initialNumToRender} 293 293 windowSize={11} 294 294 desktopFixedHeight
+2 -2
src/screens/Messages/Settings.tsx
··· 5 5 import {type NativeStackScreenProps} from '@react-navigation/native-stack' 6 6 7 7 import {type CommonNavigatorParams} from '#/lib/routes/types' 8 - import {isNative} from '#/platform/detection' 9 8 import {useUpdateActorDeclaration} from '#/state/queries/messages/actor-declaration' 10 9 import {useProfileQuery} from '#/state/queries/profile' 11 10 import {useSession} from '#/state/session' ··· 16 15 import * as Toggle from '#/components/forms/Toggle' 17 16 import * as Layout from '#/components/Layout' 18 17 import {Text} from '#/components/Typography' 18 + import {IS_NATIVE} from '#/env' 19 19 import {useBackgroundNotificationPreferences} from '../../../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' 20 20 21 21 type AllowIncoming = 'all' | 'none' | 'following' ··· 118 118 you choose. 119 119 </Trans> 120 120 </Admonition> 121 - {isNative && ( 121 + {IS_NATIVE && ( 122 122 <> 123 123 <Divider style={a.my_md} /> 124 124 <Text style={[a.text_lg, a.font_semi_bold]}>
+6 -7
src/screens/Messages/components/ChatListItem.tsx
··· 20 20 toBskyAppUrl, 21 21 toShortUrl, 22 22 } from '#/lib/strings/url-helpers' 23 - import {isNative} from '#/platform/detection' 24 23 import {useProfileShadow} from '#/state/cache/profile-shadow' 25 24 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 26 25 import {useModerationOpts} from '#/state/preferences/moderation-opts' ··· 47 46 import {Text} from '#/components/Typography' 48 47 import {useSimpleVerificationState} from '#/components/verification' 49 48 import {VerificationCheck} from '#/components/verification/VerificationCheck' 49 + import {IS_NATIVE} from '#/env' 50 50 import type * as bsky from '#/types/bsky' 51 51 52 52 export const ChatListItemPortal = createPortalGroup() ··· 142 142 143 143 const {lastMessage, lastMessageSentAt, latestReportableMessage} = 144 144 useMemo(() => { 145 - // eslint-disable-next-line @typescript-eslint/no-shadow 146 145 let lastMessage = _(msg`No messages yet`) 147 - // eslint-disable-next-line @typescript-eslint/no-shadow 146 + 148 147 let lastMessageSentAt: string | null = null 149 - // eslint-disable-next-line @typescript-eslint/no-shadow 148 + 150 149 let latestReportableMessage: ChatBskyConvoDefs.MessageView | undefined 151 150 152 151 if (ChatBskyConvoDefs.isMessageView(convo.lastMessage)) { ··· 371 370 ) 372 371 } 373 372 accessibilityActions={ 374 - isNative 373 + IS_NATIVE 375 374 ? [ 376 375 { 377 376 name: 'magicTap', ··· 385 384 : undefined 386 385 } 387 386 onPress={onPress} 388 - onLongPress={isNative ? onLongPress : undefined} 387 + onLongPress={IS_NATIVE ? onLongPress : undefined} 389 388 onAccessibilityAction={onLongPress}> 390 389 {({hovered, pressed, focused}) => ( 391 390 <View ··· 524 523 control={menuControl} 525 524 currentScreen="list" 526 525 showMarkAsRead={convo.unreadCount > 0} 527 - hideTrigger={isNative} 526 + hideTrigger={IS_NATIVE} 528 527 blockInfo={blockInfo} 529 528 style={[ 530 529 a.absolute,
+5 -5
src/screens/Messages/components/MessageInput.tsx
··· 18 18 19 19 import {HITSLOP_10, MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants' 20 20 import {useHaptics} from '#/lib/haptics' 21 - import {isIOS, isWeb} from '#/platform/detection' 22 21 import {useEmail} from '#/state/email-verification' 23 22 import { 24 23 useMessageDraft, ··· 30 29 import {android, atoms as a, useTheme} from '#/alf' 31 30 import {useSharedInputStyles} from '#/components/forms/TextField' 32 31 import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane' 32 + import {IS_IOS, IS_WEB} from '#/env' 33 33 import {useExtractEmbedFromFacets} from './MessageInputEmbed' 34 34 35 35 const AnimatedTextInput = Animated.createAnimatedComponent(TextInput) ··· 87 87 playHaptic() 88 88 setEmbed(undefined) 89 89 setMessage('') 90 - if (isIOS) { 90 + if (IS_IOS) { 91 91 setShouldEnforceClear(true) 92 92 } 93 - if (isWeb) { 93 + if (IS_WEB) { 94 94 // Pressing the send button causes the text input to lose focus, so we need to 95 95 // re-focus it after sending 96 96 setTimeout(() => { ··· 163 163 // next change and double make sure the input is cleared. It should *always* send an onChange event after 164 164 // clearing via setMessage('') that happens in onSubmit() 165 165 // -sfn 166 - if (isIOS && shouldEnforceClear) { 166 + if (IS_IOS && shouldEnforceClear) { 167 167 setShouldEnforceClear(false) 168 168 setMessage('') 169 169 return ··· 178 178 a.px_sm, 179 179 t.atoms.text, 180 180 android({paddingTop: 0}), 181 - {paddingBottom: isIOS ? 5 : 0}, 181 + {paddingBottom: IS_IOS ? 5 : 0}, 182 182 animatedStyle, 183 183 ]} 184 184 keyboardAppearance={t.scheme}
+3 -3
src/screens/Messages/components/MessageInput.web.tsx
··· 6 6 import TextareaAutosize from 'react-textarea-autosize' 7 7 import {countGraphemes} from 'unicode-segmenter/grapheme' 8 8 9 - import {isSafari, isTouchDevice} from '#/lib/browser' 10 9 import {MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants' 11 10 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 12 11 import { ··· 25 24 import {useSharedInputStyles} from '#/components/forms/TextField' 26 25 import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji' 27 26 import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane' 27 + import {IS_WEB_SAFARI, IS_WEB_TOUCH_DEVICE} from '#/env' 28 28 import {useExtractEmbedFromFacets} from './MessageInputEmbed' 29 29 30 30 export function MessageInput({ ··· 88 88 // far too long of a delay, and a subsequent enter press would often just end up doing nothing. A shorter time 89 89 // frame was also not great, since it was too short to be reliable (i.e. an older system might have a larger 90 90 // time gap between the two events firing. 91 - if (isSafari && e.key === 'Enter' && e.keyCode === 229) { 91 + if (IS_WEB_SAFARI && e.key === 'Enter' && e.keyCode === 229) { 92 92 return 93 93 } 94 94 ··· 231 231 onChange={onChange} 232 232 // On mobile web phones, we want to keep the same behavior as the native app. Do not submit the message 233 233 // in these cases. 234 - onKeyDown={isTouchDevice && isMobile ? undefined : onKeyDown} 234 + onKeyDown={IS_WEB_TOUCH_DEVICE && isMobile ? undefined : onKeyDown} 235 235 /> 236 236 <Pressable 237 237 accessibilityRole="button"
+7 -7
src/screens/Messages/components/MessagesList.tsx
··· 24 24 isBskyPostUrl, 25 25 } from '#/lib/strings/url-helpers' 26 26 import {logger} from '#/logger' 27 - import {isNative} from '#/platform/detection' 28 - import {isWeb} from '#/platform/detection' 29 27 import { 30 28 type ActiveConvoStates, 31 29 isConvoActive, ··· 52 50 import {NewMessagesPill} from '#/components/dms/NewMessagesPill' 53 51 import {Loader} from '#/components/Loader' 54 52 import {Text} from '#/components/Typography' 53 + import {IS_NATIVE} from '#/env' 54 + import {IS_WEB} from '#/env' 55 55 import {ChatStatusInfo} from './ChatStatusInfo' 56 56 import {MessageInputEmbed, useMessageEmbed} from './MessageInputEmbed' 57 57 ··· 159 159 (_: number, height: number) => { 160 160 // Because web does not have `maintainVisibleContentPosition` support, we will need to manually scroll to the 161 161 // previous off whenever we add new content to the previous offset whenever we add new content to the list. 162 - if (isWeb && isAtTop.get() && hasScrolled) { 162 + if (IS_WEB && isAtTop.get() && hasScrolled) { 163 163 flatListRef.current?.scrollToOffset({ 164 164 offset: height - prevContentHeight.current, 165 165 animated: false, ··· 399 399 (e: LayoutChangeEvent) => { 400 400 layoutHeight.set(e.nativeEvent.layout.height) 401 401 402 - if (isWeb || !keyboardIsOpening.get()) { 402 + if (IS_WEB || !keyboardIsOpening.get()) { 403 403 flatListRef.current?.scrollToEnd({ 404 404 animated: !layoutScrollWithoutAnimation.get(), 405 405 }) ··· 438 438 disableVirtualization={true} 439 439 style={animatedListStyle} 440 440 // The extra two items account for the header and the footer components 441 - initialNumToRender={isNative ? 32 : 62} 442 - maxToRenderPerBatch={isWeb ? 32 : 62} 441 + initialNumToRender={IS_NATIVE ? 32 : 62} 442 + maxToRenderPerBatch={IS_WEB ? 32 : 62} 443 443 keyboardDismissMode="on-drag" 444 444 keyboardShouldPersistTaps="handled" 445 445 maintainVisibleContentPosition={{ ··· 477 477 )} 478 478 </Animated.View> 479 479 480 - {isWeb && ( 480 + {IS_WEB && ( 481 481 <EmojiPicker 482 482 pinToTop 483 483 state={emojiPickerState}
+2 -2
src/screens/Moderation/index.tsx
··· 11 11 type NativeStackScreenProps, 12 12 } from '#/lib/routes/types' 13 13 import {logger} from '#/logger' 14 - import {isIOS} from '#/platform/detection' 15 14 import {useIsBirthdateUpdateAllowed} from '#/state/birthdate' 16 15 import { 17 16 useMyLabelersQuery, ··· 45 44 import {GlobalLabelPreference} from '#/components/moderation/LabelPreference' 46 45 import {Text} from '#/components/Typography' 47 46 import {useAgeAssurance} from '#/ageAssurance' 47 + import {IS_IOS} from '#/env' 48 48 49 49 function ErrorState({error}: {error: string}) { 50 50 const t = useTheme() ··· 182 182 (optimisticAdultContent && optimisticAdultContent.enabled) || 183 183 (!optimisticAdultContent && preferences.moderationPrefs.adultContentEnabled) 184 184 ) 185 - const adultContentUIDisabledOnIOS = isIOS && !adultContentEnabled 185 + const adultContentUIDisabledOnIOS = IS_IOS && !adultContentEnabled 186 186 let adultContentUIDisabled = adultContentUIDisabledOnIOS 187 187 188 188 if (aa.flags.adultContentDisabled) {
+5 -5
src/screens/Onboarding/Layout.tsx
··· 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {isAndroid, isWeb} from '#/platform/detection' 8 7 import {useOnboardingDispatch} from '#/state/shell' 9 8 import {useOnboardingInternalState} from '#/screens/Onboarding/state' 10 9 import { ··· 21 20 import {HEADER_SLOT_SIZE} from '#/components/Layout' 22 21 import {createPortalGroup} from '#/components/Portal' 23 22 import {P, Text} from '#/components/Typography' 23 + import {IS_ANDROID, IS_WEB} from '#/env' 24 24 import {IS_INTERNAL} from '#/env' 25 25 26 26 const ONBOARDING_COL_WIDTH = 420 ··· 58 58 aria-label={dialogLabel} 59 59 accessibilityLabel={dialogLabel} 60 60 accessibilityHint={_(msg`Customizes your Bluesky experience`)} 61 - style={[isWeb ? a.fixed : a.absolute, a.inset_0, a.flex_1, t.atoms.bg]}> 61 + style={[IS_WEB ? a.fixed : a.absolute, a.inset_0, a.flex_1, t.atoms.bg]}> 62 62 {!gtMobile ? ( 63 63 <View 64 64 style={[ ··· 151 151 paddingTop: gtMobile ? 40 : headerHeight, 152 152 paddingBottom: footerHeight, 153 153 }} 154 - showsVerticalScrollIndicator={!isAndroid} 154 + showsVerticalScrollIndicator={!IS_ANDROID} 155 155 scrollIndicatorInsets={{bottom: footerHeight - insets.bottom}} 156 156 // @ts-expect-error web only --prf 157 157 dataSet={{'stable-gutters': 1}} ··· 167 167 <View 168 168 onLayout={evt => setFooterHeight(evt.nativeEvent.layout.height)} 169 169 style={[ 170 - isWeb ? a.fixed : a.absolute, 170 + IS_WEB ? a.fixed : a.absolute, 171 171 {bottom: 0, left: 0, right: 0}, 172 172 t.atoms.bg, 173 173 t.atoms.border_contrast_low, 174 174 a.border_t, 175 175 a.align_center, 176 176 gtMobile ? a.px_5xl : a.px_xl, 177 - isWeb 177 + IS_WEB 178 178 ? a.py_2xl 179 179 : { 180 180 paddingTop: tokens.space.md,
+2 -2
src/screens/Onboarding/StepFinished/index.tsx
··· 22 22 import {useRequestNotificationsPermission} from '#/lib/notifications/notifications' 23 23 import {logEvent, useGate} from '#/lib/statsig/statsig' 24 24 import {logger} from '#/logger' 25 - import {isWeb} from '#/platform/detection' 26 25 import {useSetHasCheckedForStarterPack} from '#/state/preferences/used-starter-packs' 27 26 import {getAllListMembers} from '#/state/queries/list-members' 28 27 import {preferencesQueryKey} from '#/state/queries/preferences' ··· 47 46 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 48 47 import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow' 49 48 import {Loader} from '#/components/Loader' 49 + import {IS_WEB} from '#/env' 50 50 import * as bsky from '#/types/bsky' 51 51 import {ValuePropositionPager} from './ValuePropositionPager' 52 52 ··· 305 305 306 306 <OnboardingControls.Portal> 307 307 <View style={gtMobile && [a.gap_md, a.flex_row]}> 308 - {gtMobile && (isWeb ? subStep !== 2 : true) && ( 308 + {gtMobile && (IS_WEB ? subStep !== 2 : true) && ( 309 309 <Button 310 310 disabled={saving} 311 311 color="secondary"
+3 -3
src/screens/Onboarding/StepProfile/index.tsx
··· 17 17 import {logEvent, useGate} from '#/lib/statsig/statsig' 18 18 import {isCancelledError} from '#/lib/strings/errors' 19 19 import {logger} from '#/logger' 20 - import {isNative, isWeb} from '#/platform/detection' 21 20 import { 22 21 OnboardingControls, 23 22 OnboardingDescriptionText, ··· 38 37 import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper' 39 38 import {CircleInfo_Stroke2_Corner0_Rounded} from '#/components/icons/CircleInfo' 40 39 import {Text} from '#/components/Typography' 40 + import {IS_NATIVE, IS_WEB} from '#/env' 41 41 import {type AvatarColor, avatarColors, type Emoji, emojiItems} from './types' 42 42 43 43 export interface Avatar { ··· 183 183 let image = items[0] 184 184 if (!image) return 185 185 186 - if (!isWeb) { 186 + if (!IS_WEB) { 187 187 try { 188 188 image = await openCropper({ 189 189 imageUri: image.path, ··· 200 200 201 201 // If we are on mobile, prefetching the image will load the image into memory before we try and display it, 202 202 // stopping any brief flickers. 203 - if (isNative) { 203 + if (IS_NATIVE) { 204 204 await ExpoImage.prefetch(image.path) 205 205 } 206 206
+5 -5
src/screens/Onboarding/StepSuggestedAccounts/index.tsx
··· 10 10 import {popularInterests, useInterestsDisplayNames} from '#/lib/interests' 11 11 import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted' 12 12 import {logger} from '#/logger' 13 - import {isWeb} from '#/platform/detection' 14 13 import {updateProfileShadow} from '#/state/cache/profile-shadow' 15 14 import {useLanguagePrefs} from '#/state/preferences' 16 15 import {useModerationOpts} from '#/state/preferences/moderation-opts' ··· 31 30 import {Loader} from '#/components/Loader' 32 31 import * as ProfileCard from '#/components/ProfileCard' 33 32 import * as toast from '#/components/Toast' 33 + import {IS_WEB} from '#/env' 34 34 import type * as bsky from '#/types/bsky' 35 35 import {bulkWriteFollows} from '../util' 36 36 ··· 161 161 style={[ 162 162 a.overflow_hidden, 163 163 a.mt_sm, 164 - isWeb 164 + IS_WEB 165 165 ? [a.max_w_full, web({minHeight: '100vh'})] 166 166 : {marginHorizontal: tokens.space.xl * -1}, 167 167 a.flex_1, ··· 213 213 a.mt_md, 214 214 a.border_y, 215 215 t.atoms.border_contrast_low, 216 - isWeb && [a.border_x, a.rounded_sm, a.overflow_hidden], 216 + IS_WEB && [a.border_x, a.rounded_sm, a.overflow_hidden], 217 217 ]}> 218 218 {suggestedUsers?.actors.map((user, index) => ( 219 219 <SuggestedProfileCard ··· 324 324 ...interestsDisplayNames, 325 325 } 326 326 } 327 - gutterWidth={isWeb ? 0 : tokens.space.xl} 327 + gutterWidth={IS_WEB ? 0 : tokens.space.xl} 328 328 /> 329 329 ) 330 330 } ··· 350 350 const node = cardRef.current 351 351 if (!node || hasTrackedRef.current) return 352 352 353 - if (isWeb && typeof IntersectionObserver !== 'undefined') { 353 + if (IS_WEB && typeof IntersectionObserver !== 'undefined') { 354 354 const observer = new IntersectionObserver( 355 355 entries => { 356 356 if (entries[0]?.isIntersecting && !hasTrackedRef.current) {
+2 -2
src/screens/Onboarding/index.tsx
··· 4 4 5 5 import {useEnableKeyboardControllerScreen} from '#/lib/hooks/useEnableKeyboardController' 6 6 import {useGate} from '#/lib/statsig/statsig' 7 - import {isNative} from '#/platform/detection' 8 7 import {useLanguagePrefs} from '#/state/preferences' 9 8 import { 10 9 Layout, ··· 24 23 import {useFindContactsFlowState} from '#/components/contacts/state' 25 24 import {Portal} from '#/components/Portal' 26 25 import {ScreenTransition} from '#/components/ScreenTransition' 26 + import {IS_NATIVE} from '#/env' 27 27 import {ENV} from '#/env' 28 28 import {StepFindContacts} from './StepFindContacts' 29 29 import {StepFindContactsIntro} from './StepFindContactsIntro' ··· 50 50 useIsFindContactsFeatureEnabledBasedOnGeolocation() 51 51 const showFindContacts = 52 52 ENV !== 'e2e' && 53 - isNative && 53 + IS_NATIVE && 54 54 findContactsEnabled && 55 55 !gate('disable_onboarding_find_contacts') 56 56
+7 -6
src/screens/PostThread/components/GrowthHack.tsx
··· 3 3 import {PrivacySensitive} from 'expo-privacy-sensitive' 4 4 5 5 import {useAppState} from '#/lib/hooks/useAppState' 6 - import {isIOS} from '#/platform/detection' 7 6 import {atoms as a, useTheme} from '#/alf' 8 7 import {sizes as iconSizes} from '#/components/icons/common' 9 8 import {Mark as Logo} from '#/components/icons/Logo' 9 + import {IS_IOS} from '#/env' 10 10 11 11 const ICON_SIZE = 'xl' as const 12 12 ··· 25 25 26 26 const appState = useAppState() 27 27 28 - if (!isIOS || appState !== 'active') return children 28 + if (!IS_IOS || appState !== 'active') return children 29 29 30 30 return ( 31 31 <View ··· 33 33 a.relative, 34 34 a.justify_center, 35 35 align === 'right' ? a.align_end : a.align_start, 36 - width === undefined ? {opacity: 0} : {minWidth: width}, 36 + {minWidth: width ?? iconSizes[ICON_SIZE]}, 37 37 ]}> 38 38 <PrivacySensitive 39 39 style={[ ··· 46 46 // when finding the size of the button, we need the containing 47 47 // element to have a concrete size otherwise the text will 48 48 // collapse to 0 width. so set it to a really big number 49 - // and hide the entire thing (see above) 50 - width === undefined && {width: 10000}, 49 + // and just use `pointer-events: box-none` so it doesn't interfere with the UI 50 + {width: 1000}, 51 + a.pointer_events_box_none, 51 52 ]}> 52 53 <View 53 54 onLayout={evt => setWidth(evt.nativeEvent.layout.width)} 54 55 style={[ 55 56 t.atoms.bg, 56 - // make sure it covers the icon! the won't always be a button 57 + // make sure it covers the icon! children might be undefined 57 58 {minWidth: iconSizes[ICON_SIZE], minHeight: iconSizes[ICON_SIZE]}, 58 59 ]}> 59 60 {children}
+2 -2
src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx
··· 5 5 import {useNavigation} from '@react-navigation/native' 6 6 7 7 import {logger} from '#/logger' 8 - import {isIOS} from '#/platform/detection' 9 8 import {useProfileShadow} from '#/state/cache/profile-shadow' 10 9 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 11 10 import { ··· 18 17 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 19 18 import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' 20 19 import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' 20 + import {IS_IOS} from '#/env' 21 21 import {GrowthHack} from './GrowthHack' 22 22 23 23 export function ThreadItemAnchorFollowButton({did}: {did: string}) { 24 - if (isIOS) { 24 + if (IS_IOS) { 25 25 return ( 26 26 <GrowthHack> 27 27 <ThreadItemAnchorFollowButtonInner did={did} />
-1
src/screens/PostThread/index.tsx
··· 64 64 */ 65 65 const thread = usePostThread({anchor: uri}) 66 66 const {anchor, hasParents} = useMemo(() => { 67 - // eslint-disable-next-line @typescript-eslint/no-shadow 68 67 let hasParents = false 69 68 for (const item of thread.data.items) { 70 69 if (item.type === 'threadPost' && item.depth === 0) {
+2 -2
src/screens/Profile/Header/GrowableAvatar.tsx
··· 7 7 } from 'react-native-reanimated' 8 8 import type React from 'react' 9 9 10 - import {isIOS} from '#/platform/detection' 11 10 import {usePagerHeaderContext} from '#/view/com/pager/PagerHeaderContext' 11 + import {IS_IOS} from '#/env' 12 12 13 13 export function GrowableAvatar({ 14 14 children, ··· 20 20 const pagerContext = usePagerHeaderContext() 21 21 22 22 // pagerContext should only be present on iOS, but better safe than sorry 23 - if (!pagerContext || !isIOS) { 23 + if (!pagerContext || !IS_IOS) { 24 24 return <View style={style}>{children}</View> 25 25 } 26 26
+3 -3
src/screens/Profile/Header/GrowableBanner.tsx
··· 15 15 import {useIsFetching} from '@tanstack/react-query' 16 16 import type React from 'react' 17 17 18 - import {isIOS} from '#/platform/detection' 19 18 import {RQKEY_ROOT as STARTERPACK_RQKEY_ROOT} from '#/state/queries/actor-starter-packs' 20 19 import {RQKEY_ROOT as FEED_RQKEY_ROOT} from '#/state/queries/post-feed' 21 20 import {RQKEY_ROOT as FEEDGEN_RQKEY_ROOT} from '#/state/queries/profile-feedgens' 22 21 import {RQKEY_ROOT as LIST_RQKEY_ROOT} from '#/state/queries/profile-lists' 23 22 import {usePagerHeaderContext} from '#/view/com/pager/PagerHeaderContext' 24 23 import {atoms as a} from '#/alf' 24 + import {IS_IOS} from '#/env' 25 25 26 26 const AnimatedBlurView = Animated.createAnimatedComponent(BlurView) 27 27 ··· 39 39 const pagerContext = usePagerHeaderContext() 40 40 41 41 // plain non-growable mode for Android/Web 42 - if (!pagerContext || !isIOS) { 42 + if (!pagerContext || !IS_IOS) { 43 43 return ( 44 44 <Pressable 45 45 onPress={onPress} ··· 164 164 style={[ 165 165 a.absolute, 166 166 a.inset_0, 167 - {top: topInset - (isIOS ? 15 : 0)}, 167 + {top: topInset - (IS_IOS ? 15 : 0)}, 168 168 a.justify_center, 169 169 a.align_center, 170 170 ]}>
+3 -3
src/screens/Profile/Header/Handle.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {isInvalidHandle, sanitizeHandle} from '#/lib/strings/handles' 7 - import {isIOS, isNative} from '#/platform/detection' 8 7 import {type Shadow} from '#/state/cache/types' 9 8 import {useShowLinkInHandle} from '#/state/preferences/show-link-in-handle.tsx' 10 9 import {atoms as a, useTheme, web} from '#/alf' 11 10 import {InlineLinkText} from '#/components/Link.tsx' 12 11 import {NewskieDialog} from '#/components/NewskieDialog' 13 12 import {Text} from '#/components/Typography' 13 + import {IS_IOS, IS_NATIVE} from '#/env' 14 14 15 15 export function ProfileHeaderHandle({ 16 16 profile, ··· 28 28 profile.handle, 29 29 '@', 30 30 // forceLTR handled by CSS above on web 31 - isNative, 31 + IS_NATIVE, 32 32 ) 33 33 return ( 34 34 <View 35 35 style={[a.flex_row, a.gap_sm, a.align_center, {maxWidth: '100%'}]} 36 - pointerEvents={disableTaps ? 'none' : isIOS ? 'auto' : 'box-none'}> 36 + pointerEvents={disableTaps ? 'none' : IS_IOS ? 'auto' : 'box-none'}> 37 37 <NewskieDialog profile={profile} disabled={disableTaps} /> 38 38 39 39 <Text
+3 -3
src/screens/Profile/Header/ProfileHeaderLabeler.tsx
··· 15 15 import {useHaptics} from '#/lib/haptics' 16 16 import {isAppLabeler} from '#/lib/moderation' 17 17 import {logger} from '#/logger' 18 - import {isIOS} from '#/platform/detection' 19 18 import {useProfileShadow} from '#/state/cache/profile-shadow' 20 19 import {type Shadow} from '#/state/cache/types' 21 20 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' ··· 36 35 import {RichText} from '#/components/RichText' 37 36 import * as Toast from '#/components/Toast' 38 37 import {Text} from '#/components/Typography' 38 + import {IS_IOS} from '#/env' 39 39 import {ProfileHeaderDisplayName} from './DisplayName' 40 40 import {EditProfileDialog} from './EditProfileDialog' 41 41 import {ProfileHeaderHandle} from './Handle' ··· 114 114 isPlaceholderProfile={isPlaceholderProfile}> 115 115 <View 116 116 style={[a.px_lg, a.pt_md, a.pb_sm]} 117 - pointerEvents={isIOS ? 'auto' : 'box-none'}> 117 + pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 118 118 <View 119 119 style={[a.flex_row, a.justify_end, a.align_center, a.gap_xs, a.pb_lg]} 120 - pointerEvents={isIOS ? 'auto' : 'box-none'}> 120 + pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 121 121 <HeaderLabelerButtons profile={profile} /> 122 122 </View> 123 123 <View style={[a.flex_col, a.gap_2xs, a.pt_2xs, a.pb_md]}>
+3 -3
src/screens/Profile/Header/ProfileHeaderStandard.tsx
··· 15 15 import {sanitizeDisplayName} from '#/lib/strings/display-names' 16 16 import {sanitizeHandle} from '#/lib/strings/handles' 17 17 import {logger} from '#/logger' 18 - import {isIOS} from '#/platform/detection' 19 18 import {type Shadow, useProfileShadow} from '#/state/cache/profile-shadow' 20 19 import {useDisableFollowedByMetrics} from '#/state/preferences/disable-followed-by-metrics' 21 20 import { ··· 40 39 import * as Toast from '#/components/Toast' 41 40 import {Text} from '#/components/Typography' 42 41 import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton' 42 + import {IS_IOS} from '#/env' 43 43 import {EditProfileDialog} from './EditProfileDialog' 44 44 import {ProfileHeaderHandle} from './Handle' 45 45 import {ProfileHeaderMetrics} from './Metrics' ··· 107 107 isPlaceholderProfile={isPlaceholderProfile}> 108 108 <View 109 109 style={[a.px_lg, a.pt_md, a.pb_sm, a.overflow_hidden]} 110 - pointerEvents={isIOS ? 'auto' : 'box-none'}> 110 + pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 111 111 <View 112 112 style={[ 113 113 {paddingLeft: 90}, ··· 118 118 a.pb_sm, 119 119 a.flex_wrap, 120 120 ]} 121 - pointerEvents={isIOS ? 'auto' : 'box-none'}> 121 + pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 122 122 <HeaderStandardButtons 123 123 profile={profile} 124 124 moderation={moderation}
+5 -5
src/screens/Profile/Header/Shell.tsx
··· 19 19 import {useHaptics} from '#/lib/haptics' 20 20 import {type NavigationProp} from '#/lib/routes/types' 21 21 import {logger} from '#/logger' 22 - import {isIOS} from '#/platform/detection' 23 22 import {type Shadow} from '#/state/cache/types' 24 23 import {useLightboxControls} from '#/state/lightbox' 25 24 import {useEnableSquareAvatars} from '#/state/preferences/enable-square-avatars' ··· 41 40 import {LiveStatusDialog} from '#/components/live/LiveStatusDialog' 42 41 import {LabelsOnMe} from '#/components/moderation/LabelsOnMe' 43 42 import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts' 43 + import {IS_IOS} from '#/env' 44 44 import {GrowableAvatar} from './GrowableAvatar' 45 45 import {GrowableBanner} from './GrowableBanner' 46 46 import {StatusBarShadow} from './StatusBarShadow' ··· 196 196 }, [profile.banner, moderation, _openLightboxBanner, bannerRef]) 197 197 198 198 return ( 199 - <View style={t.atoms.bg} pointerEvents={isIOS ? 'auto' : 'box-none'}> 199 + <View style={t.atoms.bg} pointerEvents={IS_IOS ? 'auto' : 'box-none'}> 200 200 <View 201 - pointerEvents={isIOS ? 'auto' : 'box-none'} 201 + pointerEvents={IS_IOS ? 'auto' : 'box-none'} 202 202 style={[a.relative, {height: 150}]}> 203 203 <StatusBarShadow /> 204 204 <GrowableBanner ··· 285 285 a.px_lg, 286 286 a.pt_xs, 287 287 a.pb_sm, 288 - isIOS ? a.pointer_events_auto : {pointerEvents: 'box-none'}, 288 + IS_IOS ? a.pointer_events_auto : {pointerEvents: 'box-none'}, 289 289 ]} 290 290 /> 291 291 ) : ( ··· 295 295 a.px_lg, 296 296 a.pt_xs, 297 297 a.pb_sm, 298 - isIOS ? a.pointer_events_auto : {pointerEvents: 'box-none'}, 298 + IS_IOS ? a.pointer_events_auto : {pointerEvents: 'box-none'}, 299 299 ]} 300 300 /> 301 301 ))}
+2 -2
src/screens/Profile/Header/StatusBarShadow.tsx
··· 5 5 import {useSafeAreaInsets} from 'react-native-safe-area-context' 6 6 import {LinearGradient} from 'expo-linear-gradient' 7 7 8 - import {isIOS} from '#/platform/detection' 9 8 import {usePagerHeaderContext} from '#/view/com/pager/PagerHeaderContext' 10 9 import {atoms as a} from '#/alf' 10 + import {IS_IOS} from '#/env' 11 11 12 12 const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient) 13 13 ··· 15 15 const {top: topInset} = useSafeAreaInsets() 16 16 const pagerContext = usePagerHeaderContext() 17 17 18 - if (isIOS && pagerContext) { 18 + if (IS_IOS && pagerContext) { 19 19 const {scrollY} = pagerContext 20 20 return <StatusBarShadowInnner scrollY={scrollY} /> 21 21 }
+2 -2
src/screens/Profile/Header/SuggestedFollows.tsx
··· 2 2 import {type AppBskyActorDefs} from '@atproto/api' 3 3 4 4 import {AccordionAnimation} from '#/lib/custom-animations/AccordionAnimation' 5 - import {isAndroid} from '#/platform/detection' 6 5 import {useModerationOpts} from '#/state/preferences/moderation-opts' 7 6 import { 8 7 useSuggestedFollowsByActorQuery, ··· 10 9 } from '#/state/queries/suggested-follows' 11 10 import {useBreakpoints} from '#/alf' 12 11 import {ProfileGrid} from '#/components/FeedInterstitials' 12 + import {IS_ANDROID} from '#/env' 13 13 14 14 const DISMISS_ANIMATION_DURATION = 200 15 15 ··· 210 210 * This issue stems from Android not allowing dragging on clickable elements in the profile header. 211 211 * Blocking the ability to scroll on Android is too much of a trade-off for now. 212 212 **/ 213 - if (isAndroid) return null 213 + if (IS_ANDROID) return null 214 214 215 215 return ( 216 216 <AccordionAnimation isExpanded={isExpanded}>
+2 -2
src/screens/Profile/Header/index.tsx
··· 17 17 import {useIsFocused} from '@react-navigation/native' 18 18 19 19 import {sanitizeHandle} from '#/lib/strings/handles' 20 - import {isNative} from '#/platform/detection' 21 20 import {useProfileShadow} from '#/state/cache/profile-shadow' 22 21 import {useModerationOpts} from '#/state/preferences/moderation-opts' 23 22 import {useSetLightStatusBar} from '#/state/shell/light-status-bar' ··· 26 25 import {atoms as a, useTheme} from '#/alf' 27 26 import {Header} from '#/components/Layout' 28 27 import * as ProfileCard from '#/components/ProfileCard' 28 + import {IS_NATIVE} from '#/env' 29 29 import { 30 30 HeaderLabelerButtons, 31 31 ProfileHeaderLabeler, ··· 83 83 84 84 return ( 85 85 <> 86 - {isNative && ( 86 + {IS_NATIVE && ( 87 87 <MinimalHeader 88 88 onLayout={evt => setMinimumHeight(evt.nativeEvent.layout.height)} 89 89 profile={props.profile}
+3 -3
src/screens/Profile/ProfileFeed/index.tsx
··· 17 17 import {type NavigationProp} from '#/lib/routes/types' 18 18 import {makeRecordUri} from '#/lib/strings/url-helpers' 19 19 import {s} from '#/lib/styles' 20 - import {isNative} from '#/platform/detection' 21 20 import {listenSoftReset} from '#/state/events' 22 21 import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' 23 22 import { ··· 47 46 } from '#/screens/Profile/components/ProfileFeedHeader' 48 47 import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 49 48 import * as Layout from '#/components/Layout' 49 + import {IS_NATIVE} from '#/env' 50 50 51 51 type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeed'> 52 52 export function ProfileFeedScreen(props: Props) { ··· 175 175 176 176 const onScrollToTop = useCallback(() => { 177 177 scrollElRef.current?.scrollToOffset({ 178 - animated: isNative, 178 + animated: IS_NATIVE, 179 179 offset: 0, // -headerHeight, 180 180 }) 181 181 truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) ··· 204 204 const feedIsVideoMode = 205 205 feedInfo.contentMode === AppBskyFeedDefs.CONTENTMODEVIDEO 206 206 const _isVideoFeed = isBskyVideoFeed || feedIsVideoMode 207 - return isNative && _isVideoFeed 207 + return IS_NATIVE && _isVideoFeed 208 208 }, [feedInfo]) 209 209 210 210 return (
+4 -4
src/screens/Profile/Sections/Feed.tsx
··· 5 5 import {useQueryClient} from '@tanstack/react-query' 6 6 7 7 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 8 - import {isIOS, isNative} from '#/platform/detection' 9 8 import { 10 9 type FeedDescriptor, 11 10 RQKEY as FEED_RQKEY, ··· 21 20 import {atoms as a, ios, useTheme} from '#/alf' 22 21 import {EditBig_Stroke1_Corner0_Rounded as EditIcon} from '#/components/icons/EditBig' 23 22 import {Text} from '#/components/Typography' 23 + import {IS_IOS, IS_NATIVE} from '#/env' 24 24 import {type SectionRef} from './types' 25 25 26 26 interface FeedSectionProps { ··· 53 53 const [hasNew, setHasNew] = useState(false) 54 54 const [isScrolledDown, setIsScrolledDown] = useState(false) 55 55 const shouldUseAdjustedNumToRender = feed.endsWith('posts_and_author_threads') 56 - const isVideoFeed = isNative && feed.endsWith('posts_with_video') 56 + const isVideoFeed = IS_NATIVE && feed.endsWith('posts_with_video') 57 57 const adjustedInitialNumToRender = useInitialNumToRender({ 58 58 screenHeightOffset: headerHeight, 59 59 }) 60 60 const onScrollToTop = useCallback(() => { 61 61 scrollElRef.current?.scrollToOffset({ 62 - animated: isNative, 62 + animated: IS_NATIVE, 63 63 offset: -headerHeight, 64 64 }) 65 65 truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) ··· 85 85 }, [_, emptyStateButton, emptyStateIcon, emptyStateMessage]) 86 86 87 87 useEffect(() => { 88 - if (isIOS && isFocused && scrollElRef.current) { 88 + if (IS_IOS && isFocused && scrollElRef.current) { 89 89 const nativeTag = findNodeHandle(scrollElRef.current) 90 90 setScrollViewTag(nativeTag) 91 91 }
+3 -3
src/screens/Profile/Sections/Labels.tsx
··· 10 10 import {useLingui} from '@lingui/react' 11 11 12 12 import {isLabelerSubscribed, lookupLabelValueDefinition} from '#/lib/moderation' 13 - import {isIOS, isNative} from '#/platform/detection' 14 13 import {List, type ListRef} from '#/view/com/util/List' 15 14 import {atoms as a, ios, tokens, useTheme} from '#/alf' 16 15 import {Divider} from '#/components/Divider' ··· 19 18 import {Loader} from '#/components/Loader' 20 19 import {LabelerLabelPreference} from '#/components/moderation/LabelPreference' 21 20 import {Text} from '#/components/Typography' 21 + import {IS_IOS, IS_NATIVE} from '#/env' 22 22 import {ErrorState} from '../ErrorState' 23 23 import {type SectionRef} from './types' 24 24 ··· 49 49 50 50 const onScrollToTop = useCallback(() => { 51 51 scrollElRef.current?.scrollToOffset({ 52 - animated: isNative, 52 + animated: IS_NATIVE, 53 53 offset: -headerHeight, 54 54 }) 55 55 }, [scrollElRef, headerHeight]) ··· 59 59 })) 60 60 61 61 useEffect(() => { 62 - if (isIOS && isFocused && scrollElRef.current) { 62 + if (IS_IOS && isFocused && scrollElRef.current) { 63 63 const nativeTag = findNodeHandle(scrollElRef.current) 64 64 setScrollViewTag(nativeTag) 65 65 }
+3 -3
src/screens/Profile/components/ProfileFeedHeader.tsx
··· 11 11 import {sanitizeHandle} from '#/lib/strings/handles' 12 12 import {toShareUrl} from '#/lib/strings/url-helpers' 13 13 import {logger} from '#/logger' 14 - import {isWeb} from '#/platform/detection' 15 14 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 16 15 import {type FeedSourceFeedInfo} from '#/state/queries/feed' 17 16 import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like' ··· 53 52 } from '#/components/moderation/ReportDialog' 54 53 import {RichText} from '#/components/RichText' 55 54 import {Text} from '#/components/Typography' 55 + import {IS_WEB} from '#/env' 56 56 57 57 export function ProfileFeedHeaderSkeleton() { 58 58 const t = useTheme() ··· 194 194 style={[ 195 195 a.justify_start, 196 196 { 197 - paddingVertical: isWeb ? 2 : 4, 197 + paddingVertical: IS_WEB ? 2 : 4, 198 198 paddingRight: 8, 199 199 }, 200 200 ]} ··· 213 213 t.atoms.bg_contrast_25, 214 214 { 215 215 opacity: 0, 216 - left: isWeb ? -2 : -4, 216 + left: IS_WEB ? -2 : -4, 217 217 right: 0, 218 218 }, 219 219 pressed && {
+2 -2
src/screens/ProfileList/AboutSection.tsx
··· 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {isNative} from '#/platform/detection' 8 7 import {useSession} from '#/state/session' 9 8 import {ListMembers} from '#/view/com/lists/ListMembers' 10 9 import {EmptyState} from '#/view/com/util/EmptyState' ··· 14 13 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15 14 import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 16 15 import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 16 + import {IS_NATIVE} from '#/env' 17 17 18 18 interface SectionRef { 19 19 scrollToTop: () => void ··· 42 42 43 43 const onScrollToTop = useCallback(() => { 44 44 scrollElRef.current?.scrollToOffset({ 45 - animated: isNative, 45 + animated: IS_NATIVE, 46 46 offset: -headerHeight, 47 47 }) 48 48 }, [scrollElRef, headerHeight])
+2 -2
src/screens/ProfileList/FeedSection.tsx
··· 5 5 import {useIsFocused} from '@react-navigation/native' 6 6 import {useQueryClient} from '@tanstack/react-query' 7 7 8 - import {isNative} from '#/platform/detection' 9 8 import {listenSoftReset} from '#/state/events' 10 9 import { 11 10 type FeedDescriptor, ··· 19 18 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 20 19 import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 21 20 import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 21 + import {IS_NATIVE} from '#/env' 22 22 23 23 interface SectionRef { 24 24 scrollToTop: () => void ··· 51 51 52 52 const onScrollToTop = useCallback(() => { 53 53 scrollElRef.current?.scrollToOffset({ 54 - animated: isNative, 54 + animated: IS_NATIVE, 55 55 offset: -headerHeight, 56 56 }) 57 57 queryClient.resetQueries({queryKey: FEED_RQKEY(feed)})
+4 -4
src/screens/ProfileList/components/MoreOptionsMenu.tsx
··· 7 7 import {shareUrl} from '#/lib/sharing' 8 8 import {toShareUrl} from '#/lib/strings/url-helpers' 9 9 import {logger} from '#/logger' 10 - import {isWeb} from '#/platform/detection' 11 10 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 12 11 import { 13 12 useListBlockMutation, ··· 35 34 } from '#/components/moderation/ReportDialog' 36 35 import * as Prompt from '#/components/Prompt' 37 36 import * as Toast from '#/components/Toast' 37 + import {IS_WEB} from '#/env' 38 38 39 39 export function MoreOptionsMenu({ 40 40 list, ··· 165 165 <Menu.Outer> 166 166 <Menu.Group> 167 167 <Menu.Item 168 - label={isWeb ? _(msg`Copy link to list`) : _(msg`Share via...`)} 168 + label={IS_WEB ? _(msg`Copy link to list`) : _(msg`Share via...`)} 169 169 onPress={onPressShare}> 170 170 <Menu.ItemText> 171 - {isWeb ? ( 171 + {IS_WEB ? ( 172 172 <Trans>Copy link to list</Trans> 173 173 ) : ( 174 174 <Trans>Share via...</Trans> ··· 176 176 </Menu.ItemText> 177 177 <Menu.ItemIcon 178 178 position="right" 179 - icon={isWeb ? ChainLink : ShareIcon} 179 + icon={IS_WEB ? ChainLink : ShareIcon} 180 180 /> 181 181 </Menu.Item> 182 182 {savedFeedConfig && (
+11 -11
src/screens/Search/Shell.tsx
··· 22 22 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 23 23 import {MagnifyingGlassIcon} from '#/lib/icons' 24 24 import {type NavigationProp} from '#/lib/routes/types' 25 - import {isWeb} from '#/platform/detection' 26 25 import {listenSoftReset} from '#/state/events' 27 26 import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' 28 27 import { ··· 41 40 import {SearchInput} from '#/components/forms/SearchInput' 42 41 import * as Layout from '#/components/Layout' 43 42 import {Text} from '#/components/Typography' 43 + import {IS_WEB} from '#/env' 44 44 import {account, useStorage} from '#/storage' 45 45 import type * as bsky from '#/types/bsky' 46 46 import {AutocompleteResults} from './components/AutocompleteResults' ··· 141 141 const [headerHeight, setHeaderHeight] = useState(0) 142 142 const headerRef = useRef(null) 143 143 useLayoutEffect(() => { 144 - if (isWeb) { 144 + if (IS_WEB) { 145 145 if (!headerRef.current) return 146 146 const measurement = (headerRef.current as Element).getBoundingClientRect() 147 147 setHeaderHeight(measurement.height) ··· 150 150 151 151 useFocusEffect( 152 152 useNonReactiveCallback(() => { 153 - if (isWeb) { 153 + if (IS_WEB) { 154 154 setSearchText(queryParam) 155 155 } 156 156 }), ··· 173 173 setShowAutocomplete(false) 174 174 updateSearchHistory(item) 175 175 176 - if (isWeb) { 176 + if (IS_WEB) { 177 177 // @ts-expect-error route is not typesafe 178 178 navigation.push(route.name, {...route.params, q: item}) 179 179 } else { ··· 188 188 scrollToTopWeb() 189 189 textInput.current?.blur() 190 190 setShowAutocomplete(false) 191 - if (isWeb) { 191 + if (IS_WEB) { 192 192 // Empty params resets the URL to be /search rather than /search?q= 193 193 // Also clear the tab parameter 194 194 const { ··· 211 211 }, [navigateToItem, searchText]) 212 212 213 213 const onAutocompleteResultPress = useCallback(() => { 214 - if (isWeb) { 214 + if (IS_WEB) { 215 215 setShowAutocomplete(false) 216 216 } else { 217 217 textInput.current?.blur() ··· 238 238 ) 239 239 240 240 const onSoftReset = useCallback(() => { 241 - if (isWeb) { 241 + if (IS_WEB) { 242 242 // Empty params resets the URL to be /search rather than /search?q= 243 243 // Also clear the tab parameter when soft resetting 244 244 const { ··· 265 265 ) 266 266 267 267 const onSearchInputFocus = useCallback(() => { 268 - if (isWeb) { 268 + if (IS_WEB) { 269 269 // Prevent a jump on iPad by ensuring that 270 270 // the initial focused render has no result list. 271 271 requestAnimationFrame(() => { ··· 282 282 283 283 // If a tab is specified, set the tab parameter 284 284 if (tab) { 285 - if (isWeb) { 285 + if (IS_WEB) { 286 286 navigation.setParams({...route.params, tab}) 287 287 } else { 288 288 navigation.setParams({tab}) ··· 299 299 <View 300 300 ref={headerRef} 301 301 onLayout={evt => { 302 - if (isWeb) setHeaderHeight(evt.nativeEvent.layout.height) 302 + if (IS_WEB) setHeaderHeight(evt.nativeEvent.layout.height) 303 303 }} 304 304 style={[ 305 305 a.relative, ··· 581 581 } 582 582 583 583 function scrollToTopWeb() { 584 - if (isWeb) { 584 + if (IS_WEB) { 585 585 window.scrollTo(0, 0) 586 586 } 587 587 }
+2 -2
src/screens/Search/components/AutocompleteResults.tsx
··· 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {isNative} from '#/platform/detection' 8 7 import {useModerationOpts} from '#/state/preferences/moderation-opts' 9 8 import {SearchLinkCard} from '#/view/shell/desktop/Search' 10 9 import {SearchProfileCard} from '#/screens/Search/components/SearchProfileCard' 11 10 import {atoms as a, native, useTheme} from '#/alf' 12 11 import * as Layout from '#/components/Layout' 12 + import {IS_NATIVE} from '#/env' 13 13 14 14 let AutocompleteResults = ({ 15 15 isAutocompleteFetching, ··· 46 46 label={_(msg`Search for "${searchText}"`)} 47 47 onPress={native(onSubmit)} 48 48 to={ 49 - isNative 49 + IS_NATIVE 50 50 ? undefined 51 51 : `/search?q=${encodeURIComponent(searchText)}` 52 52 }
+2 -2
src/screens/Search/modules/ExploreRecommendations.tsx
··· 3 3 import {Trans} from '@lingui/macro' 4 4 5 5 import {logger} from '#/logger' 6 - import {isWeb} from '#/platform/detection' 7 6 import { 8 7 DEFAULT_LIMIT as RECOMMENDATIONS_COUNT, 9 8 useTrendingTopics, ··· 17 16 TrendingTopicSkeleton, 18 17 } from '#/components/TrendingTopics' 19 18 import {Text} from '#/components/Typography' 19 + import {IS_WEB} from '#/env' 20 20 21 21 // Note: This module is not currently used and may be removed in the future. 22 22 ··· 37 37 <View 38 38 style={[ 39 39 a.flex_row, 40 - isWeb 40 + IS_WEB 41 41 ? [a.px_lg, a.py_lg, a.pt_2xl, a.gap_md] 42 42 : [a.p_lg, a.pt_2xl, a.gap_md], 43 43 a.border_b,
+4 -4
src/screens/Settings/AboutSettings.tsx
··· 9 9 10 10 import {STATUS_PAGE_URL} from '#/lib/constants' 11 11 import {type CommonNavigatorParams} from '#/lib/routes/types' 12 - import {isAndroid, isIOS, isNative} from '#/platform/detection' 13 12 import * as Toast from '#/view/com/util/Toast' 14 13 import * as SettingsList from '#/screens/Settings/components/SettingsList' 15 14 import {Atom_Stroke2_Corner0_Rounded as AtomIcon} from '#/components/icons/Atom' ··· 20 19 import {Wrench_Stroke2_Corner2_Rounded as WrenchIcon} from '#/components/icons/Wrench' 21 20 import * as Layout from '#/components/Layout' 22 21 import {Loader} from '#/components/Loader' 22 + import {IS_ANDROID, IS_IOS, IS_NATIVE} from '#/env' 23 23 import * as env from '#/env' 24 24 import {useDemoMode} from '#/storage/hooks/demo-mode' 25 25 import {useDevMode} from '#/storage/hooks/dev-mode' ··· 42 42 return spaceDiff * -1 43 43 }, 44 44 onSuccess: sizeDiffBytes => { 45 - if (isAndroid) { 45 + if (IS_ANDROID) { 46 46 Toast.show( 47 47 _( 48 48 msg({ ··· 108 108 <Trans>System log</Trans> 109 109 </SettingsList.ItemText> 110 110 </SettingsList.LinkItem> 111 - {isNative && ( 111 + {IS_NATIVE && ( 112 112 <SettingsList.PressableItem 113 113 onPress={() => onClearImageCache()} 114 114 label={_(msg`Clear image cache`)} ··· 157 157 {devModeEnabled && ( 158 158 <> 159 159 <OTAInfo /> 160 - {isIOS && ( 160 + {IS_IOS && ( 161 161 <SettingsList.PressableItem 162 162 onPress={() => { 163 163 const newDemoModeEnabled = !demoModeEnabled
+2 -2
src/screens/Settings/AccessibilitySettings.tsx
··· 3 3 import {type NativeStackScreenProps} from '@react-navigation/native-stack' 4 4 5 5 import {type CommonNavigatorParams} from '#/lib/routes/types' 6 - import {isNative} from '#/platform/detection' 7 6 import { 8 7 useHapticsDisabled, 9 8 useRequireAltTextEnabled, ··· 20 19 import {Accessibility_Stroke2_Corner2_Rounded as AccessibilityIcon} from '#/components/icons/Accessibility' 21 20 import {Haptic_Stroke2_Corner2_Rounded as HapticIcon} from '#/components/icons/Haptic' 22 21 import * as Layout from '#/components/Layout' 22 + import {IS_NATIVE} from '#/env' 23 23 24 24 type Props = NativeStackScreenProps< 25 25 CommonNavigatorParams, ··· 76 76 <Toggle.Platform /> 77 77 </Toggle.Item> 78 78 </SettingsList.Group> 79 - {isNative && ( 79 + {IS_NATIVE && ( 80 80 <> 81 81 <SettingsList.Divider /> 82 82 <SettingsList.Group contentContainerStyle={[a.gap_sm]}>
+3 -3
src/screens/Settings/AppIconSettings/index.tsx
··· 8 8 import {PressableScale} from '#/lib/custom-animations/PressableScale' 9 9 import {type CommonNavigatorParams} from '#/lib/routes/types' 10 10 import {useGate} from '#/lib/statsig/statsig' 11 - import {isAndroid} from '#/platform/detection' 12 11 import {AppIconImage} from '#/screens/Settings/AppIconSettings/AppIconImage' 13 12 import {type AppIconSet} from '#/screens/Settings/AppIconSettings/types' 14 13 import {useAppIconSets} from '#/screens/Settings/AppIconSettings/useAppIconSets' ··· 16 15 import * as Toggle from '#/components/forms/Toggle' 17 16 import * as Layout from '#/components/Layout' 18 17 import {Text} from '#/components/Typography' 18 + import {IS_ANDROID} from '#/env' 19 19 import {IS_INTERNAL} from '#/env' 20 20 21 21 type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppIconSettings'> ··· 29 29 ) 30 30 31 31 const onSetAppIcon = (icon: DynamicAppIcon.IconName) => { 32 - if (isAndroid) { 32 + if (IS_ANDROID) { 33 33 const next = 34 34 sets.defaults.find(i => i.id === icon) ?? 35 35 sets.core.find(i => i.id === icon) ··· 221 221 accessibilityHint={_(msg`Changes app icon`)} 222 222 targetScale={0.95} 223 223 onPress={() => { 224 - if (isAndroid) { 224 + if (IS_ANDROID) { 225 225 Alert.alert( 226 226 _(msg`Change app icon to "${icon.name}"`), 227 227 _(msg`The app will be restarted`),
+52 -2
src/screens/Settings/AppearanceSettings.tsx
··· 13 13 type CommonNavigatorParams, 14 14 type NativeStackScreenProps, 15 15 } from '#/lib/routes/types' 16 - import {isNative} from '#/platform/detection' 17 16 import { 18 17 useEnableSquareAvatars, 19 18 useSetEnableSquareAvatars, ··· 39 38 import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase' 40 39 import * as Layout from '#/components/Layout' 41 40 import {Text} from '#/components/Typography' 41 + import {IS_NATIVE} from '#/env' 42 42 import {IS_INTERNAL} from '#/env' 43 43 import * as SettingsList from './components/SettingsList' 44 44 ··· 308 308 </Toggle.Item> 309 309 </SettingsList.Group> 310 310 311 - {isNative && IS_INTERNAL && ( 311 + <SettingsList.Divider /> 312 + 313 + <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 314 + <SettingsList.ItemIcon icon={SparkleIcon} /> 315 + <SettingsList.ItemText> 316 + <Trans>Logo</Trans> 317 + </SettingsList.ItemText> 318 + <Toggle.Item 319 + name="kawaii_mode" 320 + label={_(msg`Enable kawaii logo`)} 321 + value={kawaiiMode} 322 + onChange={value => setKawaiiMode(value)} 323 + style={[a.w_full]}> 324 + <Toggle.LabelText style={[a.flex_1]}> 325 + <Trans>Enable kawaii logo</Trans> 326 + </Toggle.LabelText> 327 + <Toggle.Platform /> 328 + </Toggle.Item> 329 + </SettingsList.Group> 330 + 331 + <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 332 + <SettingsList.ItemIcon icon={SquareIcon} /> 333 + <SettingsList.ItemText> 334 + <Trans>Shapes</Trans> 335 + </SettingsList.ItemText> 336 + <Toggle.Item 337 + name="enable_square_avatars" 338 + label={_(msg`Enable square avatars`)} 339 + value={enableSquareAvatars} 340 + onChange={value => setEnableSquareAvatars(value)} 341 + style={[a.w_full]}> 342 + <Toggle.LabelText style={[a.flex_1]}> 343 + <Trans>Enable square avatars</Trans> 344 + </Toggle.LabelText> 345 + <Toggle.Platform /> 346 + </Toggle.Item> 347 + 348 + <Toggle.Item 349 + name="enable_square_buttons" 350 + label={_(msg`Enable square buttons`)} 351 + value={enableSquareButtons} 352 + onChange={value => setEnableSquareButtons(value)} 353 + style={[a.w_full]}> 354 + <Toggle.LabelText style={[a.flex_1]}> 355 + <Trans>Enable square buttons</Trans> 356 + </Toggle.LabelText> 357 + <Toggle.Platform /> 358 + </Toggle.Item> 359 + </SettingsList.Group> 360 + 361 + {IS_NATIVE && IS_INTERNAL && ( 312 362 <> 313 363 <SettingsList.Divider /> 314 364 <AppIconSettingsListItem />
+2 -2
src/screens/Settings/ContentAndMediaSettings.tsx
··· 4 4 5 5 import {type CommonNavigatorParams} from '#/lib/routes/types' 6 6 import {logEvent} from '#/lib/statsig/statsig' 7 - import {isNative} from '#/platform/detection' 8 7 import {useAutoplayDisabled, useSetAutoplayDisabled} from '#/state/preferences' 9 8 import { 10 9 useInAppBrowser, ··· 26 25 import {Trending2_Stroke2_Corner2_Rounded as Graph} from '#/components/icons/Trending' 27 26 import {Window_Stroke2_Corner2_Rounded as WindowIcon} from '#/components/icons/Window' 28 27 import * as Layout from '#/components/Layout' 28 + import {IS_NATIVE} from '#/env' 29 29 import {LiveEventFeedsSettingsToggle} from '#/features/liveEvents/components/LiveEventFeedsSettingsToggle' 30 30 31 31 type Props = NativeStackScreenProps< ··· 97 97 </SettingsList.ItemText> 98 98 </SettingsList.LinkItem> 99 99 <SettingsList.Divider /> 100 - {isNative && ( 100 + {IS_NATIVE && ( 101 101 <Toggle.Item 102 102 name="use_in_app_browser" 103 103 label={_(msg`Use in-app browser to open links`)}
+3 -3
src/screens/Settings/DeerSettings.tsx
··· 15 15 useDangerousSetGate, 16 16 useGatesCache, 17 17 } from '#/lib/statsig/statsig' 18 - import {isWeb} from '#/platform/detection' 19 18 import * as persisted from '#/state/persisted' 20 19 import {useGoLinksEnabled, useSetGoLinksEnabled} from '#/state/preferences' 21 20 import { ··· 133 132 import * as Layout from '#/components/Layout' 134 133 import {Text} from '#/components/Typography' 135 134 import {SearchProfileCard} from '../Search/components/SearchProfileCard' 135 + import { IS_WEB } from '#/env/index.web' 136 136 type Props = NativeStackScreenProps<CommonNavigatorParams> 137 137 138 138 function ConstellationInstanceDialog({ ··· 188 188 )} 189 189 /> 190 190 191 - <View style={isWeb && [a.flex_row, a.justify_end]}> 191 + <View style={IS_WEB && [a.flex_row, a.justify_end]}> 192 192 <Button 193 193 label={_(msg`Save`)} 194 194 size="large" ··· 316 316 </Text> 317 317 )} 318 318 319 - <View style={isWeb && [a.flex_row, a.justify_end]}> 319 + <View style={IS_WEB && [a.flex_row, a.justify_end]}> 320 320 <Button 321 321 label={_(msg`Save`)} 322 322 size="large"
+2 -2
src/screens/Settings/FindContactsSettings.tsx
··· 20 20 } from '#/lib/routes/types' 21 21 import {cleanError, isNetworkError} from '#/lib/strings/errors' 22 22 import {logger} from '#/logger' 23 - import {isNative} from '#/platform/detection' 24 23 import { 25 24 updateProfileShadow, 26 25 useProfileShadow, ··· 48 47 import * as ProfileCard from '#/components/ProfileCard' 49 48 import * as Toast from '#/components/Toast' 50 49 import {Text} from '#/components/Typography' 50 + import {IS_NATIVE} from '#/env' 51 51 import type * as bsky from '#/types/bsky' 52 52 import {bulkWriteFollows} from '../Onboarding/util' 53 53 ··· 78 78 </Layout.Header.Content> 79 79 <Layout.Header.Slot /> 80 80 </Layout.Header.Outer> 81 - {isNative ? ( 81 + {IS_NATIVE ? ( 82 82 data ? ( 83 83 !data.syncStatus ? ( 84 84 <Intro />
+5 -5
src/screens/Settings/NotificationSettings/index.tsx
··· 11 11 type AllNavigatorParams, 12 12 type NativeStackScreenProps, 13 13 } from '#/lib/routes/types' 14 - import {isAndroid, isIOS, isWeb} from '#/platform/detection' 15 14 import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings' 16 15 import {atoms as a} from '#/alf' 17 16 import {Admonition} from '#/components/Admonition' ··· 31 30 } from '#/components/icons/Repost' 32 31 import {Shapes_Stroke2_Corner0_Rounded as ShapesIcon} from '#/components/icons/Shapes' 33 32 import * as Layout from '#/components/Layout' 33 + import {IS_ANDROID, IS_IOS, IS_WEB} from '#/env' 34 34 import * as SettingsList from '../components/SettingsList' 35 35 import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle' 36 36 ··· 45 45 const {data: permissions, refetch} = useQuery({ 46 46 queryKey: RQKEY, 47 47 queryFn: async () => { 48 - if (isWeb) return null 48 + if (IS_WEB) return null 49 49 return await Notification.getPermissionsAsync() 50 50 }, 51 51 }) ··· 58 58 }, [appState, refetch]) 59 59 60 60 const onRequestPermissions = async () => { 61 - if (isWeb) return 61 + if (IS_WEB) return 62 62 if (permissions?.canAskAgain) { 63 63 const response = await Notification.requestPermissionsAsync() 64 64 queryClient.setQueryData(RQKEY, response) 65 65 } else { 66 - if (isAndroid) { 66 + if (IS_ANDROID) { 67 67 try { 68 68 await Linking.sendIntent( 69 69 'android.settings.APP_NOTIFICATION_SETTINGS', ··· 77 77 } catch { 78 78 Linking.openSettings() 79 79 } 80 - } else if (isIOS) { 80 + } else if (IS_IOS) { 81 81 Linking.openSettings() 82 82 } 83 83 }
+4 -4
src/screens/Settings/Settings.tsx
··· 19 19 import {useGate} from '#/lib/statsig/statsig' 20 20 import {sanitizeDisplayName} from '#/lib/strings/display-names' 21 21 import {sanitizeHandle} from '#/lib/strings/handles' 22 - import {isIOS, isNative} from '#/platform/detection' 23 22 import {useProfileShadow} from '#/state/cache/profile-shadow' 24 23 import * as persisted from '#/state/persisted' 25 24 import {clearStorage} from '#/state/persisted' ··· 73 72 shouldShowVerificationCheckButton, 74 73 VerificationCheckButton, 75 74 } from '#/components/verification/VerificationCheckButton' 75 + import {IS_IOS, IS_NATIVE} from '#/env' 76 76 import {IS_INTERNAL} from '#/env' 77 77 import {device, useStorage} from '#/storage' 78 78 import {useActivitySubscriptionsNudged} from '#/storage/hooks/activity-subscriptions-nudged' ··· 215 215 <Trans>Content and media</Trans> 216 216 </SettingsList.ItemText> 217 217 </SettingsList.LinkItem> 218 - {isNative && 218 + {IS_NATIVE && 219 219 findContactsEnabled && 220 220 !gate('disable_settings_find_contacts') && ( 221 221 <SettingsList.LinkItem ··· 518 518 <Trans>Clear all storage data (restart after this)</Trans> 519 519 </SettingsList.ItemText> 520 520 </SettingsList.PressableItem> 521 - {isIOS ? ( 521 + {IS_IOS ? ( 522 522 <SettingsList.PressableItem 523 523 onPress={onPressApplyOta} 524 524 label={_(msg`Apply Pull Request`)}> ··· 527 527 </SettingsList.ItemText> 528 528 </SettingsList.PressableItem> 529 529 ) : null} 530 - {isNative && isCurrentlyRunningPullRequestDeployment ? ( 530 + {IS_NATIVE && isCurrentlyRunningPullRequestDeployment ? ( 531 531 <SettingsList.PressableItem 532 532 onPress={revertToEmbedded} 533 533 label={_(msg`Unapply Pull Request`)}>
+2 -2
src/screens/Settings/components/AddAppPasswordDialog.tsx
··· 13 13 import {useLingui} from '@lingui/react' 14 14 import {useMutation} from '@tanstack/react-query' 15 15 16 - import {isWeb} from '#/platform/detection' 17 16 import {useAppPasswordCreateMutation} from '#/state/queries/app-passwords' 18 17 import {atoms as a, native, useTheme} from '#/alf' 19 18 import {Admonition} from '#/components/Admonition' ··· 24 23 import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' 25 24 import {SquareBehindSquare4_Stroke2_Corner0_Rounded as CopyIcon} from '#/components/icons/SquareBehindSquare4' 26 25 import {Text} from '#/components/Typography' 26 + import {IS_WEB} from '#/env' 27 27 import {CopyButton} from './CopyButton' 28 28 29 29 export function AddAppPasswordDialog({ ··· 181 181 ) : ( 182 182 <Animated.View 183 183 style={[a.gap_lg]} 184 - entering={isWeb ? FadeIn.delay(200) : SlideInRight} 184 + entering={IS_WEB ? FadeIn.delay(200) : SlideInRight} 185 185 key={1}> 186 186 <Text style={[a.text_2xl, a.font_semi_bold]}> 187 187 <Trans>Here is your app password!</Trans>
+2 -2
src/screens/Settings/components/ChangePasswordDialog.tsx
··· 7 7 import {cleanError, isNetworkError} from '#/lib/strings/errors' 8 8 import {checkAndFormatResetCode} from '#/lib/strings/password' 9 9 import {logger} from '#/logger' 10 - import {isNative} from '#/platform/detection' 11 10 import {useAgent, useSession} from '#/state/session' 12 11 import {pdsAgent} from '#/state/session/agent' 13 12 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' ··· 17 16 import * as TextField from '#/components/forms/TextField' 18 17 import {Loader} from '#/components/Loader' 19 18 import {Text} from '#/components/Typography' 19 + import {IS_NATIVE} from '#/env' 20 20 21 21 enum Stages { 22 22 RequestCode = 'RequestCode', ··· 243 243 <Trans>Already have a code?</Trans> 244 244 </ButtonText> 245 245 </Button> 246 - {isNative && ( 246 + {IS_NATIVE && ( 247 247 <Button 248 248 label={_(msg`Cancel`)} 249 249 color="secondary"
+2 -2
src/screens/Settings/components/DisableEmail2FADialog.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {cleanError} from '#/lib/strings/errors' 7 - import {isNative} from '#/platform/detection' 8 7 import {useAgent, useSession} from '#/state/session' 9 8 import {pdsAgent} from '#/state/session/agent' 10 9 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' ··· 16 15 import {Lock_Stroke2_Corner0_Rounded as Lock} from '#/components/icons/Lock' 17 16 import {Loader} from '#/components/Loader' 18 17 import {P, Text} from '#/components/Typography' 18 + import {IS_NATIVE} from '#/env' 19 19 20 20 enum Stages { 21 21 Email, ··· 194 194 </View> 195 195 ) : undefined} 196 196 197 - {!gtMobile && isNative && <View style={{height: 40}} />} 197 + {!gtMobile && IS_NATIVE && <View style={{height: 40}} />} 198 198 </View> 199 199 </Dialog.ScrollableInner> 200 200 </Dialog.Outer>
+8 -6
src/screens/Signup/StepCaptcha/index.tsx
··· 7 7 8 8 import {createFullHandle} from '#/lib/strings/handles' 9 9 import {logger} from '#/logger' 10 - import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection' 11 10 import {useSignupContext} from '#/screens/Signup/state' 12 11 import {CaptchaWebView} from '#/screens/Signup/StepCaptcha/CaptchaWebView' 13 12 import {atoms as a, useTheme} from '#/alf' 14 13 import {FormError} from '#/components/forms/FormError' 14 + import {IS_ANDROID, IS_IOS, IS_NATIVE, IS_WEB} from '#/env' 15 15 import {GCP_PROJECT_ID} from '#/env' 16 16 import {BackNextButtons} from '../BackNextButtons' 17 17 18 18 const CAPTCHA_PATH = 19 - isWeb || GCP_PROJECT_ID === 0 ? '/gate/signup' : '/gate/signup/attempt-attest' 19 + IS_WEB || GCP_PROJECT_ID === 0 20 + ? '/gate/signup' 21 + : '/gate/signup/attempt-attest' 20 22 21 23 export function StepCaptcha() { 22 - if (isWeb) { 24 + if (IS_WEB) { 23 25 return <StepCaptchaInner /> 24 26 } else { 25 27 return <StepCaptchaNative /> ··· 35 37 ;(async () => { 36 38 logger.debug('trying to generate attestation token...') 37 39 try { 38 - if (isIOS) { 40 + if (IS_IOS) { 39 41 logger.debug('starting to generate devicecheck token...') 40 42 const token = await ReactNativeDeviceAttest.getDeviceCheckToken() 41 43 setToken(token) ··· 86 88 newUrl.searchParams.set('state', stateParam) 87 89 newUrl.searchParams.set('colorScheme', theme.name) 88 90 89 - if (isNative && token) { 91 + if (IS_NATIVE && token) { 90 92 newUrl.searchParams.set('platform', Platform.OS) 91 93 newUrl.searchParams.set('token', token) 92 - if (isAndroid && payload) { 94 + if (IS_ANDROID && payload) { 93 95 newUrl.searchParams.set('payload', payload) 94 96 } 95 97 }
+4 -4
src/screens/Signup/StepInfo/index.tsx
··· 8 8 import {DEFAULT_SERVICE} from '#/lib/constants' 9 9 import {isEmailMaybeInvalid} from '#/lib/strings/email' 10 10 import {logger} from '#/logger' 11 - import {isNative, isWeb} from '#/platform/detection' 12 11 import {useSignupContext} from '#/screens/Signup/state' 13 12 import {Policies} from '#/screens/Signup/StepInfo/Policies' 14 13 import {atoms as a, native} from '#/alf' ··· 37 36 MIN_ACCESS_AGE, 38 37 useAgeAssuranceRegionConfigWithFallback, 39 38 } from '#/ageAssurance/util' 39 + import {IS_NATIVE, IS_WEB} from '#/env' 40 40 import { 41 41 useDeviceGeolocationApi, 42 42 useIsDeviceGeolocationGranted, ··· 215 215 If you have one, sign in with an existing Bluesky account. 216 216 </Trans> 217 217 </Text> 218 - <View style={isWeb && [a.flex_row, a.justify_center]}> 218 + <View style={IS_WEB && [a.flex_row, a.justify_center]}> 219 219 <Button 220 220 testID="signInButton" 221 221 onPress={onPressSignIn} ··· 397 397 </Trans> 398 398 )} 399 399 </Admonition.Text> 400 - {isNative && 400 + {IS_NATIVE && 401 401 !isDeviceGeolocationGranted && 402 402 isOverAppMinAccessAge && ( 403 403 <Admonition.Text> ··· 429 429 ) : undefined} 430 430 </View> 431 431 432 - {isNative && ( 432 + {IS_NATIVE && ( 433 433 <DeviceLocationRequestDialog 434 434 control={locationControl} 435 435 onLocationAcquired={props => {
+2 -2
src/screens/Signup/index.tsx
··· 8 8 9 9 import {FEEDBACK_FORM_URL} from '#/lib/constants' 10 10 import {logger} from '#/logger' 11 - import {isAndroid} from '#/platform/detection' 12 11 import {useServiceQuery} from '#/state/queries/service' 13 12 import {useStarterPackQuery} from '#/state/queries/starter-packs' 14 13 import {useActiveStarterPack} from '#/state/shell/starter-pack' ··· 30 29 import {InlineLinkText} from '#/components/Link' 31 30 import {ScreenTransition} from '#/components/ScreenTransition' 32 31 import {Text} from '#/components/Typography' 32 + import {IS_ANDROID} from '#/env' 33 33 import {GCP_PROJECT_ID} from '#/env' 34 34 import * as bsky from '#/types/bsky' 35 35 ··· 114 114 115 115 // On Android, warmup the Play Integrity API on the signup screen so it is ready by the time we get to the gate screen. 116 116 useEffect(() => { 117 - if (!isAndroid) { 117 + if (!IS_ANDROID) { 118 118 return 119 119 } 120 120 ReactNativeDeviceAttest.warmupIntegrity(GCP_PROJECT_ID).catch(err =>
+3 -3
src/screens/SignupQueued.tsx
··· 6 6 import {useLingui} from '@lingui/react' 7 7 8 8 import {logger} from '#/logger' 9 - import {isIOS, isWeb} from '#/platform/detection' 10 9 import {isSignupQueued, useAgent, useSessionApi} from '#/state/session' 11 10 import {pdsAgent} from '#/state/session/agent' 12 11 import {useOnboardingDispatch} from '#/state/shell' ··· 15 14 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 16 15 import {Loader} from '#/components/Loader' 17 16 import {P, Text} from '#/components/Typography' 17 + import {IS_IOS, IS_WEB} from '#/env' 18 18 19 19 const COL_WIDTH = 400 20 20 ··· 99 99 </Button> 100 100 ) 101 101 102 - const webLayout = isWeb && gtMobile 102 + const webLayout = IS_WEB && gtMobile 103 103 104 104 return ( 105 105 <Modal ··· 107 107 animationType={native('slide')} 108 108 presentationStyle="formSheet" 109 109 style={[web(a.util_screen_outer)]}> 110 - {isIOS && <SystemBars style={{statusBar: 'light'}} />} 110 + {IS_IOS && <SystemBars style={{statusBar: 'light'}} />} 111 111 <ScrollView 112 112 style={[a.flex_1, t.atoms.bg]} 113 113 contentContainerStyle={{borderWidth: 0}}
+3 -4
src/screens/StarterPack/StarterPackLandingScreen.tsx
··· 11 11 import {msg, Trans} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 13 14 - import {isAndroidWeb} from '#/lib/browser' 15 14 import {JOINED_THIS_WEEK} from '#/lib/constants' 16 15 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 17 16 import {logEvent} from '#/lib/statsig/statsig' 18 17 import {createStarterPackGooglePlayUri} from '#/lib/strings/starter-pack' 19 - import {isWeb} from '#/platform/detection' 20 18 import {useModerationOpts} from '#/state/preferences/moderation-opts' 21 19 import {useStarterPackQuery} from '#/state/queries/starter-packs' 22 20 import { ··· 38 36 import * as Prompt from '#/components/Prompt' 39 37 import {RichText} from '#/components/RichText' 40 38 import {Text} from '#/components/Typography' 39 + import {IS_WEB, IS_WEB_MOBILE_ANDROID} from '#/env' 41 40 import * as bsky from '#/types/bsky' 42 41 43 42 const AnimatedPressable = Animated.createAnimatedComponent(Pressable) ··· 142 141 postAppClipMessage({ 143 142 action: 'present', 144 143 }) 145 - } else if (isAndroidWeb) { 144 + } else if (IS_WEB_MOBILE_ANDROID) { 146 145 androidDialogControl.open() 147 146 } else { 148 147 onContinue() ··· 359 358 /> 360 359 </Prompt.Actions> 361 360 </Prompt.Outer> 362 - {isWeb && ( 361 + {IS_WEB && ( 363 362 <meta 364 363 name="apple-itunes-app" 365 364 content="app-id=app.witchsky, app-clip-bundle-id=app.witchsky.AppClip, app-clip-display=card"
+4 -4
src/screens/StarterPack/StarterPackScreen.tsx
··· 27 27 import {cleanError} from '#/lib/strings/errors' 28 28 import {getStarterPackOgCard} from '#/lib/strings/starter-pack' 29 29 import {logger} from '#/logger' 30 - import {isWeb} from '#/platform/detection' 31 30 import {updateProfileShadow} from '#/state/cache/profile-shadow' 32 31 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 33 32 import {useModerationOpts} from '#/state/preferences/moderation-opts' ··· 73 72 import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog' 74 73 import {ShareDialog} from '#/components/StarterPack/ShareDialog' 75 74 import {Text} from '#/components/Typography' 75 + import {IS_WEB} from '#/env' 76 76 import * as bsky from '#/types/bsky' 77 77 78 78 type StarterPackScreeProps = NativeStackScreenProps< ··· 611 611 <Menu.Group> 612 612 <Menu.Item 613 613 label={ 614 - isWeb 614 + IS_WEB 615 615 ? _(msg`Copy link to starter pack`) 616 616 : _(msg`Share via...`) 617 617 } 618 618 testID="shareStarterPackLinkBtn" 619 619 onPress={onOpenShareDialog}> 620 620 <Menu.ItemText> 621 - {isWeb ? ( 621 + {IS_WEB ? ( 622 622 <Trans>Copy link</Trans> 623 623 ) : ( 624 624 <Trans>Share via...</Trans> 625 625 )} 626 626 </Menu.ItemText> 627 627 <Menu.ItemIcon 628 - icon={isWeb ? ChainLinkIcon : ArrowOutOfBoxIcon} 628 + icon={IS_WEB ? ChainLinkIcon : ArrowOutOfBoxIcon} 629 629 position="right" 630 630 /> 631 631 </Menu.Item>
+2 -2
src/screens/StarterPack/Wizard/StepProfiles.tsx
··· 4 4 import {type AppBskyActorDefs, type ModerationOpts} from '@atproto/api' 5 5 import {Trans} from '@lingui/macro' 6 6 7 - import {isNative} from '#/platform/detection' 8 7 import {useA11y} from '#/state/a11y' 9 8 import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' 10 9 import {useActorSearch} from '#/state/queries/actor-search' ··· 16 15 import {ScreenTransition} from '#/components/ScreenTransition' 17 16 import {WizardProfileCard} from '#/components/StarterPack/Wizard/WizardListCard' 18 17 import {Text} from '#/components/Typography' 18 + import {IS_NATIVE} from '#/env' 19 19 import type * as bsky from '#/types/bsky' 20 20 21 21 function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic) { ··· 89 89 onEndReached={ 90 90 !query && !screenReaderEnabled ? () => fetchNextPage() : undefined 91 91 } 92 - onEndReachedThreshold={isNative ? 2 : 0.25} 92 + onEndReachedThreshold={IS_NATIVE ? 2 : 0.25} 93 93 keyboardDismissMode="on-drag" 94 94 ListEmptyComponent={ 95 95 <View style={[a.flex_1, a.align_center, a.mt_lg, a.px_lg]}>
+3 -3
src/screens/StarterPack/Wizard/index.tsx
··· 31 31 parseStarterPackUri, 32 32 } from '#/lib/strings/starter-pack' 33 33 import {logger} from '#/logger' 34 - import {isNative} from '#/platform/detection' 35 34 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 36 35 import {useModerationOpts} from '#/state/preferences/moderation-opts' 37 36 import {useAllListMembersQuery} from '#/state/queries/list-members' ··· 60 59 import {Loader} from '#/components/Loader' 61 60 import {WizardEditListDialog} from '#/components/StarterPack/Wizard/WizardEditListDialog' 62 61 import {Text} from '#/components/Typography' 62 + import {IS_NATIVE} from '#/env' 63 63 import type * as bsky from '#/types/bsky' 64 64 import {Provider} from './State' 65 65 ··· 437 437 { 438 438 paddingBottom: a.pb_lg.paddingBottom + bottomInset, 439 439 }, 440 - isNative && [ 440 + IS_NATIVE && [ 441 441 a.border_l, 442 442 a.border_r, 443 443 t.atoms.shadow_md, ··· 603 603 a.w_full, 604 604 a.align_center, 605 605 a.gap_2xl, 606 - isNative ? a.mt_sm : a.mt_md, 606 + IS_NATIVE ? a.mt_sm : a.mt_md, 607 607 ]}> 608 608 {state.currentStep === 'Profiles' && items.length < 8 && ( 609 609 <Text
+2 -2
src/screens/Takendown.tsx
··· 14 14 } from '#/lib/constants' 15 15 import {useEnableKeyboardController} from '#/lib/hooks/useEnableKeyboardController' 16 16 import {cleanError} from '#/lib/strings/errors' 17 - import {isWeb} from '#/platform/detection' 18 17 import {useAgent, useSession, useSessionApi} from '#/state/session' 19 18 import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' 20 19 import {Logo} from '#/view/icons/Logo' ··· 24 23 import {SimpleInlineLinkText} from '#/components/Link' 25 24 import {Loader} from '#/components/Loader' 26 25 import {P, Text} from '#/components/Typography' 26 + import {IS_WEB} from '#/env' 27 27 28 28 const COL_WIDTH = 400 29 29 ··· 119 119 </Button> 120 120 ) 121 121 122 - const webLayout = isWeb && gtMobile 122 + const webLayout = IS_WEB && gtMobile 123 123 124 124 useEnableKeyboardController(true) 125 125
+4 -4
src/screens/VideoFeed/index.tsx
··· 57 57 import {cleanError} from '#/lib/strings/errors' 58 58 import {sanitizeHandle} from '#/lib/strings/handles' 59 59 import {logger} from '#/logger' 60 - import {isAndroid} from '#/platform/detection' 61 60 import {useA11y} from '#/state/a11y' 62 61 import { 63 62 POST_TOMBSTONE, ··· 102 101 import {PostControls} from '#/components/PostControls' 103 102 import {RichText} from '#/components/RichText' 104 103 import {Text} from '#/components/Typography' 104 + import {IS_ANDROID} from '#/env' 105 105 import * as bsky from '#/types/bsky' 106 106 import {Scrubber, VIDEO_PLAYER_BOTTOM_INSET} from './components/Scrubber' 107 107 ··· 591 591 embed: AppBskyEmbedVideo.View 592 592 }) { 593 593 const {bottom} = useSafeAreaInsets() 594 - const [isReady, setIsReady] = useState(!isAndroid) 594 + const [isReady, setIsReady] = useState(!IS_ANDROID) 595 595 596 596 useEventListener(player, 'timeUpdate', evt => { 597 - if (isAndroid && !isReady && evt.currentTime >= 0.05) { 597 + if (IS_ANDROID && !isReady && evt.currentTime >= 0.05) { 598 598 setIsReady(true) 599 599 } 600 600 }) ··· 921 921 </LinearGradient> 922 922 </View> 923 923 {/* 924 - {isAndroid && status === 'loading' && ( 924 + {IS_ANDROID && status === 'loading' && ( 925 925 <View 926 926 style={[ 927 927 a.absolute,
+2 -2
src/state/a11y.tsx
··· 1 1 import React from 'react' 2 2 import {AccessibilityInfo} from 'react-native' 3 3 4 - import {isWeb} from '#/platform/detection' 4 + import {IS_WEB} from '#/env' 5 5 import {PlatformInfo} from '../../modules/expo-bluesky-swiss-army' 6 6 7 7 const Context = React.createContext({ ··· 58 58 * 59 59 * @see https://github.com/necolas/react-native-web/discussions/2072 60 60 */ 61 - screenReaderEnabled: isWeb ? false : screenReaderEnabled, 61 + screenReaderEnabled: IS_WEB ? false : screenReaderEnabled, 62 62 } 63 63 }, [reduceMotionEnabled, screenReaderEnabled]) 64 64
+2 -2
src/state/dialogs/index.tsx
··· 1 1 import React from 'react' 2 2 3 - import {isWeb} from '#/platform/detection' 4 3 import {type DialogControlRefProps} from '#/components/Dialog' 5 4 import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context' 5 + import {IS_WEB} from '#/env' 6 6 import {BottomSheetNativeComponent} from '../../../modules/bottom-sheet' 7 7 8 8 interface IDialogContext { ··· 62 62 const openDialogs = React.useRef<Set<string>>(new Set()) 63 63 64 64 const closeAllDialogs = React.useCallback(() => { 65 - if (isWeb) { 65 + if (IS_WEB) { 66 66 openDialogs.current.forEach(id => { 67 67 const dialog = activeDialogs.current.get(id) 68 68 if (dialog) dialog.current.close()
+5 -5
src/state/gallery.ts
··· 19 19 import {type PickerImage} from '#/lib/media/picker.shared' 20 20 import {getDataUriSize} from '#/lib/media/util' 21 21 import {isCancelledError} from '#/lib/strings/errors' 22 - import {isNative} from '#/platform/detection' 22 + import {IS_NATIVE} from '#/env' 23 23 24 24 export type ImageTransformation = { 25 25 crop?: ActionCrop['crop'] ··· 57 57 let _imageCacheDirectory: string 58 58 59 59 function getImageCacheDirectory(): string | null { 60 - if (isNative) { 60 + if (IS_NATIVE) { 61 61 return (_imageCacheDirectory ??= joinPath(cacheDirectory!, 'bsky-composer')) 62 62 } 63 63 ··· 124 124 } 125 125 126 126 export async function cropImage(img: ComposerImage): Promise<ComposerImage> { 127 - if (!isNative) { 127 + if (!IS_NATIVE) { 128 128 return img 129 129 } 130 130 ··· 247 247 } 248 248 249 249 async function moveIfNecessary(from: string) { 250 - const cacheDir = isNative && getImageCacheDirectory() 250 + const cacheDir = IS_NATIVE && getImageCacheDirectory() 251 251 252 252 if (cacheDir && from.startsWith(cacheDir)) { 253 253 const to = joinPath(cacheDir, nanoid(36)) ··· 263 263 264 264 /** Purge files that were created to accomodate image manipulation */ 265 265 export async function purgeTemporaryImageFiles() { 266 - const cacheDir = isNative && getImageCacheDirectory() 266 + const cacheDir = IS_NATIVE && getImageCacheDirectory() 267 267 268 268 if (cacheDir) { 269 269 await deleteAsync(cacheDir, {idempotent: true})
+3 -3
src/state/messages/convo/agent.ts
··· 16 16 isNetworkError, 17 17 } from '#/lib/strings/errors' 18 18 import {Logger} from '#/logger' 19 - import {isNative} from '#/platform/detection' 20 19 import { 21 20 ACTIVE_POLL_INTERVAL, 22 21 BACKGROUND_POLL_INTERVAL, ··· 37 36 } from '#/state/messages/convo/types' 38 37 import {type MessagesEventBus} from '#/state/messages/events/agent' 39 38 import {type MessagesEventBusError} from '#/state/messages/events/types' 39 + import {IS_NATIVE} from '#/env' 40 40 41 41 const logger = Logger.create(Logger.Context.ConversationAgent) 42 42 ··· 95 95 this.convoId = params.convoId 96 96 this.agent = params.agent 97 97 this.events = params.events 98 - this.senderUserDid = params.agent.session?.did! 98 + this.senderUserDid = params.agent.assertDid 99 99 100 100 if (params.placeholderData) { 101 101 this.setupPlaceholderData(params.placeholderData) ··· 639 639 { 640 640 cursor: nextCursor, 641 641 convoId: this.convoId, 642 - limit: isNative ? 30 : 60, 642 + limit: IS_NATIVE ? 30 : 60, 643 643 }, 644 644 {headers: DM_SERVICE_HEADERS}, 645 645 )
+5
src/state/persisted/index.web.ts
··· 22 22 let _state: Schema = defaults 23 23 const _emitter = new EventEmitter() 24 24 25 + // async, to match native implementation 26 + // eslint-disable-next-line @typescript-eslint/require-await 25 27 export async function init() { 26 28 broadcast.onmessage = onBroadcastMessage 27 29 window.onstorage = onStorage ··· 37 39 } 38 40 get satisfies PersistedApi['get'] 39 41 42 + // eslint-disable-next-line @typescript-eslint/require-await 40 43 export async function write<K extends keyof Schema>( 41 44 key: K, 42 45 value: Schema[K], ··· 82 85 } 83 86 onUpdate satisfies PersistedApi['onUpdate'] 84 87 88 + // eslint-disable-next-line @typescript-eslint/require-await 85 89 export async function clearStorage() { 86 90 try { 87 91 localStorage.removeItem(BSKY_STORAGE) ··· 102 106 } 103 107 } 104 108 109 + // eslint-disable-next-line @typescript-eslint/require-await 105 110 async function onBroadcastMessage({data}: MessageEvent) { 106 111 if ( 107 112 typeof data === 'object' &&
+1 -1
src/state/preferences/index.tsx
··· 51 51 useSetExternalEmbedPref, 52 52 } from './external-embeds-prefs' 53 53 export {useGoLinksEnabled, useSetGoLinksEnabled} from './go-links-enabled' 54 - export * from './hidden-posts' 54 + export {useHiddenPosts, useHiddenPostsApi} from './hidden-posts' 55 55 export { 56 56 useHideFeedsPromoTab, 57 57 useSetHideFeedsPromoTab,
+2 -2
src/state/preferences/kawaii.tsx
··· 1 1 import React from 'react' 2 2 3 - import {isWeb} from '#/platform/detection' 4 3 import * as persisted from '#/state/persisted' 4 + import {IS_WEB} from '#/env' 5 5 6 6 type StateContext = persisted.Schema['kawaii'] 7 7 ··· 30 30 React.useEffect(() => { 31 31 // dumb and stupid but it's web only so just refresh the page if you want to change it 32 32 33 - if (isWeb) { 33 + if (IS_WEB) { 34 34 const kawaii = new URLSearchParams(window.location.search).get('kawaii') 35 35 switch (kawaii) { 36 36 case 'true':
+7 -1
src/state/queries/preferences/types.ts
··· 15 15 } 16 16 17 17 export type ThreadViewPreferences = { 18 - sort: 'hotness' | 'oldest' | 'newest' | 'most-likes' | 'random' | string 18 + sort: 19 + | 'hotness' 20 + | 'oldest' 21 + | 'newest' 22 + | 'most-likes' 23 + | 'random' 24 + | (string & {}) 19 25 lab_treeViewEnabled?: boolean 20 26 }
+2 -2
src/state/queries/usePostThread/index.ts
··· 1 1 import {useCallback, useMemo, useState} from 'react' 2 2 import {useQuery, useQueryClient} from '@tanstack/react-query' 3 3 4 - import {isWeb} from '#/platform/detection' 5 4 import {useModerationOpts} from '#/state/preferences/moderation-opts' 6 5 import {useThreadPreferences} from '#/state/queries/preferences/useThreadPreferences' 7 6 import { ··· 31 30 import {useAgent, useSession} from '#/state/session' 32 31 import {useMergeThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' 33 32 import {useBreakpoints} from '#/alf' 33 + import {IS_WEB} from '#/env' 34 34 35 35 export * from '#/state/queries/usePostThread/context' 36 36 export {useUpdatePostThreadThreadgateQueryCache} from '#/state/queries/usePostThread/queryCache' ··· 53 53 const below = useMemo(() => { 54 54 return view === 'linear' 55 55 ? LINEAR_VIEW_BELOW 56 - : isWeb && gtPhone 56 + : IS_WEB && gtPhone 57 57 ? TREE_VIEW_BELOW_DESKTOP 58 58 : TREE_VIEW_BELOW 59 59 }, [view, gtPhone])
-1
src/state/queries/usePostThread/traversal.ts
··· 1 - /* eslint-disable no-labels */ 2 1 import {AppBskyUnspeccedDefs, type ModerationOpts} from '@atproto/api' 3 2 4 3 import {
+6 -2
src/state/service-config.tsx
··· 85 85 return useContext(TrendingContext) 86 86 } 87 87 88 - const DEFAULT_LIVE_ALLOWED_DOMAINS = ['twitch.tv', 'www.twitch.tv'] 88 + const DEFAULT_LIVE_ALLOWED_DOMAINS = [ 89 + 'twitch.tv', 90 + 'www.twitch.tv', 91 + 'stream.place', 92 + ] 89 93 export type LiveNowConfig = { 90 94 allowedDomains: Set<string> 91 95 } ··· 106 110 const gate = useGate() 107 111 const {hasSession} = useSession() 108 112 if (!hasSession) return false 109 - return IS_DEV ? true : gate('live_now_beta') 113 + return IS_DEV ? true : !gate('disable_live_now_beta') 110 114 } 111 115 112 116 export function useCheckEmailConfirmed() {
+2 -2
src/state/session/index.tsx
··· 1 1 import React, {useMemo} from 'react' 2 2 import {type AtpSessionEvent, type BskyAgent} from '@atproto/api' 3 3 4 - import {isWeb} from '#/platform/detection' 5 4 import * as persisted from '#/state/persisted' 6 5 import {useCloseAllActiveElements} from '#/state/util' 7 6 import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' 7 + import {IS_WEB} from '#/env' 8 8 import {emitSessionDropped} from '../events' 9 9 import { 10 10 agentToSessionAccount, ··· 341 341 ) 342 342 343 343 // @ts-expect-error window type is not declared, debug only 344 - if (__DEV__ && isWeb) window.agent = state.currentAgentState.agent 344 + if (__DEV__ && IS_WEB) window.agent = state.currentAgentState.agent 345 345 346 346 const agent = state.currentAgentState.agent as BskyAppAgent 347 347 const currentAgentRef = React.useRef(agent)
+3 -3
src/state/shell/logged-out.tsx
··· 1 1 import React from 'react' 2 2 3 - import {isWeb} from '#/platform/detection' 4 3 import {useSession} from '#/state/session' 5 4 import {useActiveStarterPack} from '#/state/shell/starter-pack' 5 + import {IS_WEB} from '#/env' 6 6 7 7 type State = { 8 8 showLoggedOut: boolean ··· 26 26 /** 27 27 * The did of the account to populate the login form with. 28 28 */ 29 - requestedAccount?: string | 'none' | 'new' | 'starterpack' 29 + requestedAccount?: (string & {}) | 'none' | 'new' | 'starterpack' 30 30 }) => void 31 31 /** 32 32 * Clears the requested account so that next time the logged out view is ··· 55 55 const [state, setState] = React.useState<State>({ 56 56 showLoggedOut: shouldShowStarterPack, 57 57 requestedAccountSwitchTo: shouldShowStarterPack 58 - ? isWeb 58 + ? IS_WEB 59 59 ? 'starterpack' 60 60 : 'new' 61 61 : undefined,
+3 -3
src/state/shell/selected-feed.tsx
··· 1 1 import {createContext, useCallback, useContext, useState} from 'react' 2 2 3 - import {isWeb} from '#/platform/detection' 4 3 import {type FeedDescriptor} from '#/state/queries/post-feed' 5 4 import {useSession} from '#/state/session' 5 + import {IS_WEB} from '#/env' 6 6 import {account} from '#/storage' 7 7 8 8 type StateContext = FeedDescriptor | null ··· 14 14 setContext.displayName = 'SelectedFeedSetContext' 15 15 16 16 function getInitialFeed(did?: string): FeedDescriptor | null { 17 - if (isWeb) { 17 + if (IS_WEB) { 18 18 if (window.location.pathname === '/') { 19 19 const params = new URLSearchParams(window.location.search) 20 20 const feedFromUrl = params.get('feed') ··· 49 49 const saveState = useCallback( 50 50 (feed: FeedDescriptor) => { 51 51 setState(feed) 52 - if (isWeb) { 52 + if (IS_WEB) { 53 53 try { 54 54 sessionStorage.setItem('lastSelectedHomeFeed', feed) 55 55 } catch {}
+2 -2
src/view/com/auth/SplashScreen.web.tsx
··· 31 31 }) => { 32 32 const {_} = useLingui() 33 33 const t = useTheme() 34 - const {isTabletOrMobile: isMobileWeb} = useWebMediaQueries() 34 + const {isTabletOrMobile: IS_WEB_MOBILE} = useWebMediaQueries() 35 35 const [showClipOverlay, setShowClipOverlay] = React.useState(false) 36 36 37 37 React.useEffect(() => { ··· 78 78 a.justify_center, 79 79 // @ts-expect-error web only 80 80 {paddingBottom: '20vh'}, 81 - isMobileWeb && a.pb_5xl, 81 + IS_WEB_MOBILE && a.pb_5xl, 82 82 t.atoms.border_contrast_medium, 83 83 a.align_center, 84 84 a.gap_5xl,
+19 -19
src/view/com/composer/Composer.tsx
··· 76 76 import {cleanError} from '#/lib/strings/errors' 77 77 import {colors} from '#/lib/styles' 78 78 import {logger} from '#/logger' 79 - import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection' 80 79 import {useDialogStateControlContext} from '#/state/dialogs' 81 80 import {emitPostCreated} from '#/state/events' 82 81 import { ··· 132 131 import * as Prompt from '#/components/Prompt' 133 132 import * as Toast from '#/components/Toast' 134 133 import {Text as NewText} from '#/components/Typography' 134 + import {IS_ANDROID, IS_IOS, IS_NATIVE, IS_WEB} from '#/env' 135 135 import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet' 136 136 import {PostLanguageSelect} from './select-language/PostLanguageSelect' 137 137 import { ··· 331 331 const insets = useSafeAreaInsets() 332 332 const viewStyles = useMemo( 333 333 () => ({ 334 - paddingTop: isAndroid ? insets.top : 0, 334 + paddingTop: IS_ANDROID ? insets.top : 0, 335 335 paddingBottom: 336 336 // iOS - when keyboard is closed, keep the bottom bar in the safe area 337 - (isIOS && !isKeyboardVisible) || 337 + (IS_IOS && !isKeyboardVisible) || 338 338 // Android - Android >=35 KeyboardAvoidingView adds double padding when 339 339 // keyboard is closed, so we subtract that in the offset and add it back 340 340 // here when the keyboard is open 341 - (isAndroid && isKeyboardVisible) 341 + (IS_ANDROID && isKeyboardVisible) 342 342 ? insets.bottom 343 343 : 0, 344 344 }), ··· 368 368 369 369 // On Android, pressing Back should ask confirmation. 370 370 useEffect(() => { 371 - if (!isAndroid) { 371 + if (!IS_ANDROID) { 372 372 return 373 373 } 374 374 const backHandler = BackHandler.addEventListener( ··· 673 673 composerState.mutableNeedsFocusActive = false 674 674 // On Android, this risks getting the cursor stuck behind the keyboard. 675 675 // Not worth it. 676 - if (!isAndroid) { 676 + if (!IS_ANDROID) { 677 677 textInput.current?.focus() 678 678 } 679 679 } ··· 729 729 </> 730 730 ) 731 731 732 - const isWebFooterSticky = !isNative && thread.posts.length > 1 732 + const IS_WEBFooterSticky = !IS_NATIVE && thread.posts.length > 1 733 733 return ( 734 734 <BottomSheetPortalProvider> 735 735 <KeyboardAvoidingView 736 736 testID="composePostView" 737 - behavior={isIOS ? 'padding' : 'height'} 737 + behavior={IS_IOS ? 'padding' : 'height'} 738 738 keyboardVerticalOffset={keyboardVerticalOffset} 739 739 style={a.flex_1}> 740 740 <View ··· 794 794 onPublish={onComposerPostPublish} 795 795 onError={setError} 796 796 /> 797 - {isWebFooterSticky && post.id === activePost.id && ( 797 + {IS_WEBFooterSticky && post.id === activePost.id && ( 798 798 <View style={styles.stickyFooterWeb}>{footer}</View> 799 799 )} 800 800 </React.Fragment> 801 801 ))} 802 802 </Animated.ScrollView> 803 - {!isWebFooterSticky && footer} 803 + {!IS_WEBFooterSticky && footer} 804 804 </View> 805 805 806 806 <Prompt.Basic ··· 853 853 const {data: currentProfile} = useProfileQuery({did: currentDid}) 854 854 const richtext = post.richtext 855 855 const isTextOnly = !post.embed.link && !post.embed.quote && !post.embed.media 856 - const forceMinHeight = isWeb && isTextOnly && isActive 856 + const forceMinHeight = IS_WEB && isTextOnly && isActive 857 857 const selectTextInputPlaceholder = isReply 858 858 ? isFirstPost 859 859 ? _(msg`Write your reply`) ··· 895 895 async (uri: string) => { 896 896 if ( 897 897 uri.startsWith('data:video/') || 898 - (isWeb && uri.startsWith('data:image/gif')) 898 + (IS_WEB && uri.startsWith('data:image/gif')) 899 899 ) { 900 - if (isNative) return // web only 900 + if (IS_NATIVE) return // web only 901 901 const [mimeType] = uri.slice('data:'.length).split(';') 902 902 if (!SUPPORTED_MIME_TYPES.includes(mimeType as SupportedMimeTypes)) { 903 903 Toast.show(_(msg`Unsupported video type: ${mimeType}`), { ··· 927 927 a.mb_sm, 928 928 !isActive && isLastPost && a.mb_lg, 929 929 !isActive && styles.inactivePost, 930 - isTextOnly && isNative && a.flex_grow, 930 + isTextOnly && IS_NATIVE && a.flex_grow, 931 931 ]}> 932 - <View style={[a.flex_row, isNative && a.flex_1]}> 932 + <View style={[a.flex_row, IS_NATIVE && a.flex_1]}> 933 933 <UserAvatar 934 934 avatar={currentProfile?.avatar} 935 935 size={42} ··· 1270 1270 </LayoutAnimationConfig> 1271 1271 {embed.quote?.uri ? ( 1272 1272 <View 1273 - style={[a.pb_sm, video ? [a.pt_md] : [a.pt_xl], isWeb && [a.pb_md]]}> 1273 + style={[a.pb_sm, video ? [a.pt_md] : [a.pt_xl], IS_WEB && [a.pb_md]]}> 1274 1274 <View style={[a.relative]}> 1275 1275 <View style={{pointerEvents: 'none'}}> 1276 1276 <LazyQuoteEmbed uri={embed.quote.uri} /> ··· 1683 1683 const {top, bottom} = useSafeAreaInsets() 1684 1684 1685 1685 // Android etc 1686 - if (!isIOS) { 1686 + if (!IS_IOS) { 1687 1687 // need to account for the edge-to-edge nav bar 1688 1688 return bottom * -1 1689 1689 } ··· 1727 1727 const appState = useAppState() 1728 1728 1729 1729 useEffect(() => { 1730 - if (isIOS) { 1730 + if (IS_IOS) { 1731 1731 if (appState === 'inactive') { 1732 1732 Keyboard.dismiss() 1733 1733 } ··· 1879 1879 style: StyleProp<ViewStyle> 1880 1880 children: React.ReactNode 1881 1881 }) { 1882 - if (isWeb) return children 1882 + if (IS_WEB) return children 1883 1883 return ( 1884 1884 <Animated.View 1885 1885 style={style}
+2 -2
src/view/com/composer/GifAltText.tsx
··· 9 9 type EmbedPlayerParams, 10 10 parseEmbedPlayerFromUrl, 11 11 } from '#/lib/strings/embed-player' 12 - import {isAndroid} from '#/platform/detection' 13 12 import {useResolveGifQuery} from '#/state/queries/resolve-link' 14 13 import {type Gif} from '#/state/queries/tenor' 15 14 import {AltTextCounterWrapper} from '#/view/com/composer/AltTextCounterWrapper' ··· 23 22 import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' 24 23 import {GifEmbed} from '#/components/Post/Embed/ExternalEmbed/Gif' 25 24 import {Text} from '#/components/Typography' 25 + import {IS_ANDROID} from '#/env' 26 26 import {AltTextReminder} from './photos/Gallery' 27 27 28 28 export function GifAltTextDialog({ ··· 224 224 </View> 225 225 <Dialog.Close /> 226 226 {/* Maybe fix this later -h */} 227 - {isAndroid ? <View style={{height: 300}} /> : null} 227 + {IS_ANDROID ? <View style={{height: 300}} /> : null} 228 228 </Dialog.ScrollableInner> 229 229 ) 230 230 }
+2 -2
src/view/com/composer/KeyboardAccessory.tsx
··· 3 3 import {useSafeAreaInsets} from 'react-native-safe-area-context' 4 4 import type React from 'react' 5 5 6 - import {isWeb} from '#/platform/detection' 7 6 import {atoms as a, useTheme} from '#/alf' 7 + import {IS_WEB} from '#/env' 8 8 9 9 export function KeyboardAccessory({children}: {children: React.ReactNode}) { 10 10 const t = useTheme() ··· 22 22 ] 23 23 24 24 // todo: when iPad support is added, it should also not use the KeyboardStickyView 25 - if (isWeb) { 25 + if (IS_WEB) { 26 26 return <View style={style}>{children}</View> 27 27 } 28 28
+9 -9
src/view/com/composer/SelectMediaButton.tsx
··· 11 11 } from '#/lib/hooks/usePermissions' 12 12 import {openUnifiedPicker} from '#/lib/media/picker' 13 13 import {extractDataUriMime} from '#/lib/media/util' 14 - import {isNative, isWeb} from '#/platform/detection' 15 14 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 16 15 import {MAX_IMAGES} from '#/view/com/composer/state/composer' 17 16 import {atoms as a, useTheme} from '#/alf' ··· 19 18 import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper' 20 19 import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image' 21 20 import * as toast from '#/components/Toast' 21 + import {IS_NATIVE, IS_WEB} from '#/env' 22 22 23 23 export type SelectMediaButtonProps = { 24 24 disabled?: boolean ··· 92 92 'image/svg+xml', 93 93 'image/webp', 94 94 'image/avif', 95 - isNative && 'image/heic', 95 + IS_NATIVE && 'image/heic', 96 96 ] as const 97 97 ).filter(Boolean) 98 98 type SupportedImageMimeType = Exclude< ··· 262 262 * We don't care too much about mimeType at this point on native, 263 263 * since the `processVideo` step later on will convert to `.mp4`. 264 264 */ 265 - if (isWeb && !isSupportedVideoMimeType(mimeType)) { 265 + if (IS_WEB && !isSupportedVideoMimeType(mimeType)) { 266 266 errors.add(SelectedAssetError.Unsupported) 267 267 continue 268 268 } ··· 272 272 * to filter out large files on web. On native, we compress these anyway, 273 273 * so we only check on web. 274 274 */ 275 - if (isWeb && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) { 275 + if (IS_WEB && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) { 276 276 errors.add(SelectedAssetError.FileTooBig) 277 277 continue 278 278 } ··· 291 291 * to filter out large files on web. On native, we compress GIFs as 292 292 * videos anyway, so we only check on web. 293 293 */ 294 - if (isWeb && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) { 294 + if (IS_WEB && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) { 295 295 errors.add(SelectedAssetError.FileTooBig) 296 296 continue 297 297 } ··· 309 309 * base64 data-uri, so we construct it here for web only. 310 310 */ 311 311 uri: 312 - isWeb && asset.base64 312 + IS_WEB && asset.base64 313 313 ? `data:${mimeType};base64,${asset.base64}` 314 314 : asset.uri, 315 315 }) ··· 328 328 } 329 329 330 330 if (supportedAssets[0].duration) { 331 - if (isWeb) { 331 + if (IS_WEB) { 332 332 /* 333 333 * Web reports duration as seconds 334 334 */ ··· 433 433 ) 434 434 435 435 const onPressSelectMedia = useCallback(async () => { 436 - if (isNative) { 436 + if (IS_NATIVE) { 437 437 const [photoAccess, videoAccess] = await Promise.all([ 438 438 requestPhotoAccessIfNeeded(), 439 439 requestVideoAccessIfNeeded(), ··· 447 447 } 448 448 } 449 449 450 - if (isNative && Keyboard.isVisible()) { 450 + if (IS_NATIVE && Keyboard.isVisible()) { 451 451 Keyboard.dismiss() 452 452 } 453 453
+2 -2
src/view/com/composer/labels/LabelsBtn.tsx
··· 9 9 type OtherSelfLabel, 10 10 type SelfLabel, 11 11 } from '#/lib/moderation' 12 - import {isWeb} from '#/platform/detection' 13 12 import {atoms as a, useTheme, web} from '#/alf' 14 13 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15 14 import * as Dialog from '#/components/Dialog' ··· 18 17 import {TinyChevronBottom_Stroke2_Corner0_Rounded as TinyChevronIcon} from '#/components/icons/Chevron' 19 18 import {Shield_Stroke2_Corner0_Rounded} from '#/components/icons/Shield' 20 19 import {Text} from '#/components/Typography' 20 + import {IS_WEB} from '#/env' 21 21 22 22 export function LabelsBtn({ 23 23 labels, ··· 218 218 label={_(msg`Done`)} 219 219 onPress={() => control.close()} 220 220 color="primary" 221 - size={isWeb ? 'small' : 'large'} 221 + size={IS_WEB ? 'small' : 'large'} 222 222 variant="solid" 223 223 testID="confirmBtn"> 224 224 <ButtonText>
+2 -2
src/view/com/composer/photos/Gallery.tsx
··· 16 16 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 17 17 import {type Dimensions} from '#/lib/media/types' 18 18 import {colors, s} from '#/lib/styles' 19 - import {isNative} from '#/platform/detection' 20 19 import {type ComposerImage, cropImage} from '#/state/gallery' 21 20 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 22 21 import {Text} from '#/view/com/util/text/Text' 23 22 import {tokens, useTheme} from '#/alf' 24 23 import * as Dialog from '#/components/Dialog' 25 24 import {MediaInsetBorder} from '#/components/MediaInsetBorder' 25 + import {IS_NATIVE} from '#/env' 26 26 import {type PostAction} from '../state/composer' 27 27 import {EditImageDialog} from './EditImageDialog' 28 28 import {ImageAltTextDialog} from './ImageAltTextDialog' ··· 148 148 const enableSquareButtons = useEnableSquareButtons() 149 149 150 150 const onImageEdit = () => { 151 - if (isNative) { 151 + if (IS_NATIVE) { 152 152 cropImage(image).then(next => { 153 153 onChange(next) 154 154 })
+3 -3
src/view/com/composer/photos/ImageAltTextDialog.tsx
··· 6 6 7 7 import {MAX_ALT_TEXT} from '#/lib/constants' 8 8 import {enforceLen} from '#/lib/strings/helpers' 9 - import {isAndroid, isWeb} from '#/platform/detection' 10 9 import {type ComposerImage} from '#/state/gallery' 11 10 import {AltTextCounterWrapper} from '#/view/com/composer/AltTextCounterWrapper' 12 11 import {atoms as a, useTheme} from '#/alf' ··· 16 15 import * as TextField from '#/components/forms/TextField' 17 16 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 18 17 import {Text} from '#/components/Typography' 18 + import {IS_ANDROID, IS_WEB} from '#/env' 19 19 20 20 type Props = { 21 21 control: Dialog.DialogOuterProps['control'] ··· 66 66 const windim = useWindowDimensions() 67 67 68 68 const imageStyle = React.useMemo<ImageStyle>(() => { 69 - const maxWidth = isWeb ? 450 : windim.width 69 + const maxWidth = IS_WEB ? 450 : windim.width 70 70 const source = image.transformed ?? image.source 71 71 72 72 if (source.height > source.width) { ··· 165 165 </AltTextCounterWrapper> 166 166 </View> 167 167 {/* Maybe fix this later -h */} 168 - {isAndroid ? <View style={{height: 300}} /> : null} 168 + {IS_ANDROID ? <View style={{height: 300}} /> : null} 169 169 </Dialog.ScrollableInner> 170 170 ) 171 171 }
+2 -2
src/view/com/composer/photos/OpenCameraBtn.tsx
··· 7 7 import {useCameraPermission} from '#/lib/hooks/usePermissions' 8 8 import {openCamera} from '#/lib/media/picker' 9 9 import {logger} from '#/logger' 10 - import {isMobileWeb, isNative} from '#/platform/detection' 11 10 import {type ComposerImage, createComposerImage} from '#/state/gallery' 12 11 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 13 12 import {atoms as a, useTheme} from '#/alf' 14 13 import {Button} from '#/components/Button' 15 14 import {Camera_Stroke2_Corner0_Rounded as Camera} from '#/components/icons/Camera' 15 + import {IS_NATIVE, IS_WEB_MOBILE} from '#/env' 16 16 17 17 type Props = { 18 18 disabled?: boolean ··· 61 61 requestMediaPermission, 62 62 ]) 63 63 64 - const shouldShowCameraButton = isNative || isMobileWeb 64 + const shouldShowCameraButton = IS_NATIVE || IS_WEB_MOBILE 65 65 if (!shouldShowCameraButton) { 66 66 return null 67 67 }
+4 -4
src/view/com/composer/select-language/PostLanguageSelectDialog.tsx
··· 6 6 7 7 import {languageName} from '#/locale/helpers' 8 8 import {type Language, LANGUAGES, LANGUAGES_MAP_CODE2} from '#/locale/languages' 9 - import {isNative, isWeb} from '#/platform/detection' 10 9 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 11 10 import { 12 11 toPostLanguages, ··· 22 21 import * as Toggle from '#/components/forms/Toggle' 23 22 import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' 24 23 import {Text} from '#/components/Typography' 24 + import {IS_NATIVE, IS_WEB} from '#/env' 25 25 26 26 export function PostLanguageSelectDialog({ 27 27 control, ··· 171 171 172 172 const listHeader = ( 173 173 <View 174 - style={[a.pb_xs, t.atoms.bg, isNative && a.pt_2xl]} 174 + style={[a.pb_xs, t.atoms.bg, IS_NATIVE && a.pt_2xl]} 175 175 onLayout={evt => setHeaderHeight(evt.nativeEvent.layout.height)}> 176 176 <View style={[a.flex_row, a.w_full, a.justify_between]}> 177 177 <View> ··· 198 198 </Text> 199 199 </View> 200 200 201 - {isWeb && ( 201 + {IS_WEB && ( 202 202 <Button 203 203 variant="ghost" 204 204 size="small" ··· 255 255 ListHeaderComponent={listHeader} 256 256 stickyHeaderIndices={[0]} 257 257 contentContainerStyle={[a.gap_0]} 258 - style={[isNative && a.px_lg, web({paddingBottom: 120})]} 258 + style={[IS_NATIVE && a.px_lg, web({paddingBottom: 120})]} 259 259 scrollIndicatorInsets={{top: headerHeight}} 260 260 renderItem={({item, index}) => { 261 261 if (item.type === 'header') {
+6 -4
src/view/com/composer/text-input/TextInput.tsx
··· 14 14 import {AppBskyRichtextFacet, RichText, UnicodeString} from '@atproto/api' 15 15 import PasteInput, { 16 16 type PastedFile, 17 - type PasteInputRef, // @ts-expect-error no types when installing from github 17 + type PasteInputRef, 18 + // @ts-expect-error no types when installing from github 19 + // eslint-disable-next-line import-x/no-unresolved 18 20 } from '@mattermost/react-native-paste-input' 19 21 20 22 import {POST_IMG_MAX} from '#/lib/constants' ··· 23 25 import {cleanError} from '#/lib/strings/errors' 24 26 import {getMentionAt, insertMentionAt} from '#/lib/strings/mention-manip' 25 27 import {useTheme} from '#/lib/ThemeContext' 26 - import {isAndroid, isNative} from '#/platform/detection' 27 28 import { 28 29 type LinkFacetMatch, 29 30 suggestLinkCardUri, 30 31 } from '#/view/com/composer/text-input/text-input-util' 31 32 import {atoms as a, useAlf} from '#/alf' 32 33 import {normalizeTextStyles} from '#/alf/typography' 34 + import {IS_ANDROID, IS_NATIVE} from '#/env' 33 35 import {Autocomplete} from './mobile/Autocomplete' 34 36 import {type TextInputProps} from './TextInput.types' 35 37 ··· 226 228 /** 227 229 * PasteInput doesn't like `lineHeight`, results in jumpiness 228 230 */ 229 - if (isNative) { 231 + if (IS_NATIVE) { 230 232 style.lineHeight = undefined 231 233 } 232 234 233 235 /* 234 236 * Android impl of `PasteInput` doesn't support the array syntax for `fontVariant` 235 237 */ 236 - if (isAndroid) { 238 + if (IS_ANDROID) { 237 239 // @ts-ignore 238 240 style.fontVariant = style.fontVariant 239 241 ? style.fontVariant.join(' ')
+2 -2
src/view/com/composer/threadgate/ThreadgateBtn.tsx
··· 8 8 9 9 import {isNetworkError} from '#/lib/strings/errors' 10 10 import {logger} from '#/logger' 11 - import {isNative} from '#/platform/detection' 12 11 import {usePostInteractionSettingsMutation} from '#/state/queries/post-interaction-settings' 13 12 import {createPostgateRecord} from '#/state/queries/postgate/util' 14 13 import {usePreferencesQuery} from '#/state/queries/preferences' ··· 25 24 import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group' 26 25 import * as Tooltip from '#/components/Tooltip' 27 26 import {Text} from '#/components/Typography' 27 + import {IS_NATIVE} from '#/env' 28 28 import {useThreadgateNudged} from '#/storage/hooks/threadgate-nudged' 29 29 30 30 export function ThreadgateBtn({ ··· 70 70 nudged: tooltipWasShown, 71 71 }) 72 72 73 - if (isNative && Keyboard.isVisible()) { 73 + if (IS_NATIVE && Keyboard.isVisible()) { 74 74 Keyboard.dismiss() 75 75 } 76 76
+10 -6
src/view/com/composer/videos/SubtitleDialog.tsx
··· 6 6 import {MAX_ALT_TEXT} from '#/lib/constants' 7 7 import {isOverMaxGraphemeCount} from '#/lib/strings/helpers' 8 8 import {LANGUAGES} from '#/locale/languages' 9 - import {isWeb} from '#/platform/detection' 10 9 import {useLanguagePrefs} from '#/state/preferences' 11 10 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 12 11 import {atoms as a, useTheme, web} from '#/alf' ··· 18 17 import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' 19 18 import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 20 19 import {Text} from '#/components/Typography' 20 + import {IS_WEB} from '#/env' 21 21 import {SubtitleFilePicker} from './SubtitleFilePicker' 22 22 23 23 const MAX_NUM_CAPTIONS = 1 ··· 38 38 return ( 39 39 <View style={[a.flex_row, a.my_xs]}> 40 40 <Button 41 - label={isWeb ? _(msg`Captions & alt text`) : _(msg`Alt text`)} 41 + label={IS_WEB ? _(msg`Captions & alt text`) : _(msg`Alt text`)} 42 42 accessibilityHint={ 43 - isWeb 43 + IS_WEB 44 44 ? _(msg`Opens captions and alt text dialog`) 45 45 : _(msg`Opens alt text dialog`) 46 46 } ··· 53 53 }}> 54 54 <ButtonIcon icon={CCIcon} /> 55 55 <ButtonText> 56 - {isWeb ? <Trans>Captions & alt text</Trans> : <Trans>Alt text</Trans>} 56 + {IS_WEB ? ( 57 + <Trans>Captions & alt text</Trans> 58 + ) : ( 59 + <Trans>Alt text</Trans> 60 + )} 57 61 </ButtonText> 58 62 </Button> 59 63 <Dialog.Outer control={control}> ··· 135 139 </Text> 136 140 )} 137 141 138 - {isWeb && ( 142 + {IS_WEB && ( 139 143 <> 140 144 <View 141 145 style={[ ··· 183 187 <View style={web([a.flex_row, a.justify_end])}> 184 188 <Button 185 189 label={_(msg`Done`)} 186 - size={isWeb ? 'small' : 'large'} 190 + size={IS_WEB ? 'small' : 'large'} 187 191 color="primary" 188 192 variant="solid" 189 193 onPress={() => {
+2 -2
src/view/com/composer/videos/VideoTranscodeProgress.tsx
··· 4 4 import {type ImagePickerAsset} from 'expo-image-picker' 5 5 6 6 import {clamp} from '#/lib/numbers' 7 - import {isWeb} from '#/platform/detection' 8 7 import {atoms as a, useTheme} from '#/alf' 8 + import {IS_WEB} from '#/env' 9 9 import {ExternalEmbedRemoveBtn} from '../ExternalEmbedRemoveBtn' 10 10 import {VideoTranscodeBackdrop} from './VideoTranscodeBackdrop' 11 11 ··· 20 20 }) { 21 21 const t = useTheme() 22 22 23 - if (isWeb) return null 23 + if (IS_WEB) return null 24 24 25 25 let aspectRatio = asset.width / asset.height 26 26
+5 -5
src/view/com/feeds/ComposerPrompt.tsx
··· 11 11 } from '#/lib/hooks/usePermissions' 12 12 import {openCamera, openUnifiedPicker} from '#/lib/media/picker' 13 13 import {logger} from '#/logger' 14 - import {isNative} from '#/platform/detection' 15 14 import {useCurrentAccountProfile} from '#/state/queries/useCurrentAccountProfile' 16 15 import {MAX_IMAGES} from '#/view/com/composer/state/composer' 17 16 import {UserAvatar} from '#/view/com/util/UserAvatar' ··· 22 21 import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image' 23 22 import {SubtleHover} from '#/components/SubtleHover' 24 23 import {Text} from '#/components/Typography' 24 + import {IS_NATIVE} from '#/env' 25 25 26 26 export function ComposerPrompt() { 27 27 const {_} = useLingui() ··· 43 43 logger.metric('composerPrompt:gallery:press', {}) 44 44 45 45 // On web, open the composer with the gallery picker auto-opening 46 - if (!isNative) { 46 + if (!IS_NATIVE) { 47 47 openComposer({openGallery: true}) 48 48 return 49 49 } ··· 105 105 return 106 106 } 107 107 108 - if (isNative && Keyboard.isVisible()) { 108 + if (IS_NATIVE && Keyboard.isVisible()) { 109 109 Keyboard.dismiss() 110 110 } 111 111 ··· 122 122 ] 123 123 124 124 openComposer({ 125 - imageUris: isNative ? imageUris : undefined, 125 + imageUris: IS_NATIVE ? imageUris : undefined, 126 126 }) 127 127 } catch (err: any) { 128 128 if (!String(err).toLowerCase().includes('cancel')) { ··· 189 189 <Trans>What's up?</Trans> 190 190 </Text> 191 191 <View style={[a.flex_row, a.gap_md]}> 192 - {isNative && ( 192 + {IS_NATIVE && ( 193 193 <Button 194 194 onPress={e => { 195 195 e.stopPropagation()
+4 -4
src/view/com/feeds/FeedPage.tsx
··· 20 20 import {type AllNavigatorParams} from '#/lib/routes/types' 21 21 import {logEvent} from '#/lib/statsig/statsig' 22 22 import {s} from '#/lib/styles' 23 - import {isNative} from '#/platform/detection' 24 23 import {listenSoftReset} from '#/state/events' 25 24 import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' 26 25 import {useSetHomeBadge} from '#/state/home-badge' ··· 34 33 import {useSession} from '#/state/session' 35 34 import {useSetMinimalShellMode} from '#/state/shell' 36 35 import {useHeaderOffset} from '#/components/hooks/useHeaderOffset' 36 + import {IS_NATIVE} from '#/env' 37 37 import {PostFeed} from '../posts/PostFeed' 38 38 import {FAB} from '../util/fab/FAB' 39 39 import {type ListMethods} from '../util/List' ··· 80 80 const feedIsVideoMode = 81 81 feedInfo.contentMode === AppBskyFeedDefs.CONTENTMODEVIDEO 82 82 const _isVideoFeed = isBskyVideoFeed || feedIsVideoMode 83 - return isNative && _isVideoFeed 83 + return IS_NATIVE && _isVideoFeed 84 84 }, [feedInfo]) 85 85 86 86 useEffect(() => { ··· 91 91 92 92 const scrollToTop = useCallback(() => { 93 93 scrollElRef.current?.scrollToOffset({ 94 - animated: isNative, 94 + animated: IS_NATIVE, 95 95 offset: -headerOffset, 96 96 }) 97 97 setMinimalShellMode(false) ··· 136 136 }) 137 137 }, [scrollToTop, feed, queryClient]) 138 138 139 - const shouldPrefetch = isNative && isPageAdjacent 139 + const shouldPrefetch = IS_NATIVE && isPageAdjacent 140 140 const isDiscoverFeed = feedInfo.uri === DISCOVER_FEED_URI 141 141 return ( 142 142 <View
+3 -3
src/view/com/feeds/MissingFeed.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {cleanError} from '#/lib/strings/errors' 7 - import {isNative, isWeb} from '#/platform/detection' 8 7 import {useModerationOpts} from '#/state/preferences/moderation-opts' 9 8 import {getFeedTypeFromUri} from '#/state/queries/feed' 10 9 import {useProfileQuery} from '#/state/queries/profile' ··· 15 14 import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 16 15 import * as ProfileCard from '#/components/ProfileCard' 17 16 import {Text} from '#/components/Typography' 17 + import {IS_NATIVE, IS_WEB} from '#/env' 18 18 19 19 export function MissingFeed({ 20 20 style, ··· 83 83 a.italic, 84 84 ]} 85 85 numberOfLines={1}> 86 - {isWeb ? ( 86 + {IS_WEB ? ( 87 87 <Trans>Click for information</Trans> 88 88 ) : ( 89 89 <Trans>Tap for information</Trans> ··· 205 205 </> 206 206 )} 207 207 </View> 208 - {isNative && ( 208 + {IS_NATIVE && ( 209 209 <Button 210 210 label={_(msg`Close`)} 211 211 onPress={() => control.close()}
+4 -4
src/view/com/feeds/ProfileFeedgens.tsx
··· 20 20 21 21 import {cleanError} from '#/lib/strings/errors' 22 22 import {logger} from '#/logger' 23 - import {isIOS, isNative, isWeb} from '#/platform/detection' 24 23 import {usePreferencesQuery} from '#/state/queries/preferences' 25 24 import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens' 26 25 import {useSession} from '#/state/session' ··· 33 32 import * as FeedCard from '#/components/FeedCard' 34 33 import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 35 34 import {ListFooter} from '#/components/Lists' 35 + import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env' 36 36 37 37 const LOADING = {_reactKey: '__loading__'} 38 38 const EMPTY = {_reactKey: '__empty__'} ··· 111 111 112 112 const onScrollToTop = useCallback(() => { 113 113 scrollElRef.current?.scrollToOffset({ 114 - animated: isNative, 114 + animated: IS_NATIVE, 115 115 offset: -headerOffset, 116 116 }) 117 117 queryClient.invalidateQueries({queryKey: RQKEY(did)}) ··· 194 194 return ( 195 195 <View 196 196 style={[ 197 - (index !== 0 || isWeb) && a.border_t, 197 + (index !== 0 || IS_WEB) && a.border_t, 198 198 t.atoms.border_contrast_low, 199 199 a.px_lg, 200 200 a.py_lg, ··· 218 218 ) 219 219 220 220 useEffect(() => { 221 - if (isIOS && enabled && scrollElRef.current) { 221 + if (IS_IOS && enabled && scrollElRef.current) { 222 222 const nativeTag = findNodeHandle(scrollElRef.current) 223 223 setScrollViewTag(nativeTag) 224 224 }
+5 -5
src/view/com/lightbox/ImageViewing/index.tsx
··· 41 41 42 42 import {type Dimensions} from '#/lib/media/types' 43 43 import {colors, s} from '#/lib/styles' 44 - import {isIOS} from '#/platform/detection' 45 44 import {type Lightbox} from '#/state/lightbox' 46 45 import {Button} from '#/view/com/util/forms/Button' 47 46 import {Text} from '#/view/com/util/text/Text' 48 47 import {ScrollView} from '#/view/com/util/Views' 49 48 import {useTheme} from '#/alf' 50 49 import {setSystemUITheme} from '#/alf/util/systemUI' 50 + import {IS_IOS} from '#/env' 51 51 import {PlatformInfo} from '../../../../../modules/expo-bluesky-swiss-army' 52 52 import {type ImageSource, type Transform} from './@types' 53 53 import ImageDefaultHeader from './components/ImageDefaultHeader' ··· 59 59 const PIXEL_RATIO = PixelRatio.get() 60 60 61 61 const SLOW_SPRING: WithSpringConfig = { 62 - mass: isIOS ? 1.25 : 0.75, 62 + mass: IS_IOS ? 1.25 : 0.75, 63 63 damping: 300, 64 64 stiffness: 800, 65 65 restDisplacementThreshold: 0.01, 66 66 } 67 67 const FAST_SPRING: WithSpringConfig = { 68 - mass: isIOS ? 1.25 : 0.75, 68 + mass: IS_IOS ? 1.25 : 0.75, 69 69 damping: 150, 70 70 stiffness: 900, 71 71 restDisplacementThreshold: 0.01, ··· 248 248 ) 249 249 opacity -= dragProgress 250 250 } 251 - const factor = isIOS ? 100 : 50 251 + const factor = IS_IOS ? 100 : 50 252 252 return { 253 253 opacity: Math.round(opacity * factor) / factor, 254 254 } ··· 686 686 maxHeight: '100%', 687 687 }, 688 688 footerText: { 689 - paddingBottom: isIOS ? 20 : 16, 689 + paddingBottom: IS_IOS ? 20 : 16, 690 690 }, 691 691 footerBtns: { 692 692 flexDirection: 'row',
+4 -4
src/view/com/lists/ProfileLists.tsx
··· 20 20 21 21 import {cleanError} from '#/lib/strings/errors' 22 22 import {logger} from '#/logger' 23 - import {isIOS, isNative, isWeb} from '#/platform/detection' 24 23 import {usePreferencesQuery} from '#/state/queries/preferences' 25 24 import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists' 26 25 import {useSession} from '#/state/session' ··· 33 32 import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 34 33 import * as ListCard from '#/components/ListCard' 35 34 import {ListFooter} from '#/components/Lists' 35 + import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env' 36 36 37 37 const LOADING = {_reactKey: '__loading__'} 38 38 const EMPTY = {_reactKey: '__empty__'} ··· 111 111 112 112 const onScrollToTop = useCallback(() => { 113 113 scrollElRef.current?.scrollToOffset({ 114 - animated: isNative, 114 + animated: IS_NATIVE, 115 115 offset: -headerOffset, 116 116 }) 117 117 queryClient.invalidateQueries({queryKey: RQKEY(did)}) ··· 193 193 return ( 194 194 <View 195 195 style={[ 196 - (index !== 0 || isWeb) && a.border_t, 196 + (index !== 0 || IS_WEB) && a.border_t, 197 197 t.atoms.border_contrast_low, 198 198 a.px_lg, 199 199 a.py_lg, ··· 217 217 ) 218 218 219 219 useEffect(() => { 220 - if (isIOS && enabled && scrollElRef.current) { 220 + if (IS_IOS && enabled && scrollElRef.current) { 221 221 const nativeTag = findNodeHandle(scrollElRef.current) 222 222 setScrollViewTag(nativeTag) 223 223 }
+3 -3
src/view/com/modals/DeleteAccount.tsx
··· 16 16 import {cleanError} from '#/lib/strings/errors' 17 17 import {colors, gradients, s} from '#/lib/styles' 18 18 import {useTheme} from '#/lib/ThemeContext' 19 - import {isAndroid, isWeb} from '#/platform/detection' 20 19 import {useModalControls} from '#/state/modals' 21 20 import {useAgent, useSession, useSessionApi} from '#/state/session' 22 21 import {pdsAgent} from '#/state/session/agent' 23 22 import {atoms as a, useTheme as useNewTheme} from '#/alf' 24 23 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 25 24 import {Text as NewText} from '#/components/Typography' 25 + import {IS_ANDROID, IS_WEB} from '#/env' 26 26 import {resetToTab} from '../../../Navigation' 27 27 import {ErrorMessage} from '../util/error/ErrorMessage' 28 28 import {Text} from '../util/text/Text' 29 29 import * as Toast from '../util/Toast' 30 30 import {ScrollView, TextInput} from './util' 31 31 32 - export const snapPoints = isAndroid ? ['90%'] : ['55%'] 32 + export const snapPoints = IS_ANDROID ? ['90%'] : ['55%'] 33 33 34 34 export function Component({}: {}) { 35 35 const pal = usePalette('default') ··· 174 174 </> 175 175 )} 176 176 177 - <View style={[!isWeb && a.px_xl]}> 177 + <View style={[!IS_WEB && a.px_xl]}> 178 178 <View 179 179 style={[ 180 180 a.w_full,
+6 -6
src/view/com/modals/UserAddRemoveLists.tsx
··· 14 14 import {cleanError} from '#/lib/strings/errors' 15 15 import {sanitizeHandle} from '#/lib/strings/handles' 16 16 import {s} from '#/lib/styles' 17 - import {useTheme} from '#/lib/ThemeContext' 18 - import {isAndroid, isMobileWeb, isWeb} from '#/platform/detection' 17 + import {useTheme} from '#/alf' 19 18 import {useModalControls} from '#/state/modals' 20 19 import { 21 20 getMembership, ··· 25 24 useListMembershipRemoveMutation, 26 25 } from '#/state/queries/list-memberships' 27 26 import {useSession} from '#/state/session' 27 + import {IS_ANDROID, IS_WEB, IS_WEB_MOBILE} from '#/env' 28 28 import {MyLists} from '../lists/MyLists' 29 29 import {Button} from '../util/forms/Button' 30 30 import {Text} from '../util/text/Text' ··· 57 57 }, [closeModal]) 58 58 59 59 const listStyle = React.useMemo(() => { 60 - if (isMobileWeb) { 60 + if (IS_WEB_MOBILE) { 61 61 return [pal.border, {height: screenHeight / 2}] 62 - } else if (isWeb) { 62 + } else if (IS_WEB) { 63 63 return [pal.border, {height: screenHeight / 1.5}] 64 64 } 65 65 ··· 245 245 246 246 const styles = StyleSheet.create({ 247 247 container: { 248 - paddingHorizontal: isWeb ? 0 : 16, 248 + paddingHorizontal: IS_WEB ? 0 : 16, 249 249 }, 250 250 btns: { 251 251 position: 'relative', ··· 254 254 justifyContent: 'center', 255 255 gap: 10, 256 256 paddingTop: 10, 257 - paddingBottom: isAndroid ? 10 : 0, 257 + paddingBottom: IS_ANDROID ? 10 : 0, 258 258 borderTopWidth: StyleSheet.hairlineWidth, 259 259 }, 260 260 footerBtn: {
+2 -2
src/view/com/pager/PagerHeaderContext.tsx
··· 1 1 import React, {useContext} from 'react' 2 2 import {type SharedValue} from 'react-native-reanimated' 3 3 4 - import {isNative} from '#/platform/detection' 4 + import {IS_NATIVE} from '#/env' 5 5 6 6 export const PagerHeaderContext = React.createContext<{ 7 7 scrollY: SharedValue<number> ··· 37 37 38 38 export function usePagerHeaderContext() { 39 39 const ctx = useContext(PagerHeaderContext) 40 - if (isNative) { 40 + if (IS_NATIVE) { 41 41 if (!ctx) { 42 42 throw new Error( 43 43 'usePagerHeaderContext must be used within a HeaderProvider',
+3 -3
src/view/com/pager/PagerWithHeader.tsx
··· 18 18 19 19 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 20 20 import {ScrollProvider} from '#/lib/ScrollContext' 21 - import {isIOS} from '#/platform/detection' 22 21 import { 23 22 Pager, 24 23 type PagerRef, 25 24 type RenderTabBarFnProps, 26 25 } from '#/view/com/pager/Pager' 27 26 import {useTheme} from '#/alf' 27 + import {IS_IOS} from '#/env' 28 28 import {type ListMethods} from '../util/List' 29 29 import {PagerHeaderProvider} from './PagerHeaderContext' 30 30 import {TabBar} from './TabBar' ··· 273 273 const headerRef = useRef(null) 274 274 return ( 275 275 <Animated.View 276 - pointerEvents={isIOS ? 'auto' : 'box-none'} 276 + pointerEvents={IS_IOS ? 'auto' : 'box-none'} 277 277 style={[styles.tabBarMobile, headerTransform, t.atoms.bg]}> 278 278 <View 279 279 ref={headerRef} 280 - pointerEvents={isIOS ? 'auto' : 'box-none'} 280 + pointerEvents={IS_IOS ? 'auto' : 'box-none'} 281 281 collapsable={false}> 282 282 {renderHeader?.({setMinimumHeight: setMinimumHeaderHeight})} 283 283 {
+2 -2
src/view/com/posts/CustomFeedEmptyState.tsx
··· 13 13 import {type NavigationProp} from '#/lib/routes/types' 14 14 import {s} from '#/lib/styles' 15 15 import {logger} from '#/logger' 16 - import {isWeb} from '#/platform/detection' 17 16 import {useFeedFeedbackContext} from '#/state/feed-feedback' 18 17 import {useSession} from '#/state/session' 18 + import {IS_WEB} from '#/env' 19 19 import {Button} from '../util/forms/Button' 20 20 import {Text} from '../util/text/Text' 21 21 ··· 44 44 const navigation = useNavigation<NavigationProp>() 45 45 46 46 const onPressFindAccounts = React.useCallback(() => { 47 - if (isWeb) { 47 + if (IS_WEB) { 48 48 navigation.navigate('Search', {}) 49 49 } else { 50 50 navigation.navigate('SearchTab')
+2 -2
src/view/com/posts/FollowingEmptyState.tsx
··· 11 11 import {MagnifyingGlassIcon} from '#/lib/icons' 12 12 import {type NavigationProp} from '#/lib/routes/types' 13 13 import {s} from '#/lib/styles' 14 - import {isWeb} from '#/platform/detection' 14 + import {IS_WEB} from '#/env' 15 15 import {Button} from '../util/forms/Button' 16 16 import {Text} from '../util/text/Text' 17 17 ··· 21 21 const navigation = useNavigation<NavigationProp>() 22 22 23 23 const onPressFindAccounts = React.useCallback(() => { 24 - if (isWeb) { 24 + if (IS_WEB) { 25 25 navigation.navigate('Search', {}) 26 26 } else { 27 27 navigation.navigate('SearchTab')
+2 -2
src/view/com/posts/FollowingEndOfFeed.tsx
··· 10 10 import {usePalette} from '#/lib/hooks/usePalette' 11 11 import {type NavigationProp} from '#/lib/routes/types' 12 12 import {s} from '#/lib/styles' 13 - import {isWeb} from '#/platform/detection' 13 + import {IS_WEB} from '#/env' 14 14 import {Button} from '../util/forms/Button' 15 15 import {Text} from '../util/text/Text' 16 16 ··· 20 20 const navigation = useNavigation<NavigationProp>() 21 21 22 22 const onPressFindAccounts = React.useCallback(() => { 23 - if (isWeb) { 23 + if (IS_WEB) { 24 24 navigation.navigate('Search', {}) 25 25 } else { 26 26 navigation.navigate('SearchTab')
+4 -5
src/view/com/posts/PostFeed.tsx
··· 34 34 import {logEvent, useGate} from '#/lib/statsig/statsig' 35 35 import {isNetworkError} from '#/lib/strings/errors' 36 36 import {logger} from '#/logger' 37 - import {isIOS, isNative, isWeb} from '#/platform/detection' 38 37 import {usePostAuthorShadowFilter} from '#/state/cache/profile-shadow' 39 38 import {listenPostCreated} from '#/state/events' 40 39 import {useFeedFeedbackContext} from '#/state/feed-feedback' ··· 72 71 } from '#/components/feeds/PostFeedVideoGridRow' 73 72 import {TrendingInterstitial} from '#/components/interstitials/Trending' 74 73 import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interstitials/TrendingVideos' 74 + import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env' 75 75 import {DiscoverFeedLiveEventFeedsAndTrendingBanner} from '#/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner' 76 76 import {ComposerPrompt} from '../feeds/ComposerPrompt' 77 77 import {DiscoverFallbackHeader} from './DiscoverFallbackHeader' ··· 314 314 const [feedType, feedUriOrActorDid, feedTab] = feed.split('|') 315 315 const {gtMobile} = useBreakpoints() 316 316 const {rightNavVisible} = useLayoutBreakpoints() 317 - const areVideoFeedsEnabled = isNative 317 + const areVideoFeedsEnabled = IS_NATIVE 318 318 319 319 const [hasPressedShowLessUris, setHasPressedShowLessUris] = useState( 320 320 () => new Set<string>(), ··· 514 514 for (const page of data.pages) { 515 515 for (const slice of page.slices) { 516 516 const item = slice.items.find( 517 - // eslint-disable-next-line @typescript-eslint/no-shadow 518 517 item => item.uri === slice.feedPostUri, 519 518 ) 520 519 if ( ··· 986 985 * reach the end, so that content isn't cut off by the bottom of the 987 986 * screen. 988 987 */ 989 - const offset = Math.max(headerOffset, 32) * (isWeb ? 1 : 2) 988 + const offset = Math.max(headerOffset, 32) * (IS_WEB ? 1 : 2) 990 989 991 990 return isFetchingNextPage ? ( 992 991 <View style={[styles.feedFooter]}> ··· 1137 1136 } 1138 1137 initialNumToRender={initialNumToRenderOverride ?? initialNumToRender} 1139 1138 windowSize={9} 1140 - maxToRenderPerBatch={isIOS ? 5 : 1} 1139 + maxToRenderPerBatch={IS_IOS ? 5 : 1} 1141 1140 updateCellsBatchingPeriod={40} 1142 1141 onItemSeen={onItemSeen} 1143 1142 />
+2 -2
src/view/com/profile/ProfileFollows.tsx
··· 8 8 import {type NavigationProp} from '#/lib/routes/types' 9 9 import {cleanError} from '#/lib/strings/errors' 10 10 import {logger} from '#/logger' 11 - import {isWeb} from '#/platform/detection' 12 11 import {useProfileFollowsQuery} from '#/state/queries/profile-follows' 13 12 import {useResolveDidQuery} from '#/state/queries/resolve-uri' 14 13 import {useSession} from '#/state/session' 15 14 import {FindContactsBannerNUX} from '#/components/contacts/FindContactsBannerNUX' 16 15 import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2' 17 16 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 17 + import {IS_WEB} from '#/env' 18 18 import {List} from '../util/List' 19 19 import {ProfileCardWithFollowBtn} from './ProfileCard' 20 20 ··· 49 49 const navigation = useNavigation<NavigationProp>() 50 50 51 51 const onPressFindAccounts = React.useCallback(() => { 52 - if (isWeb) { 52 + if (IS_WEB) { 53 53 navigation.navigate('Search', {}) 54 54 } else { 55 55 navigation.navigate('SearchTab')
+10 -8
src/view/com/profile/ProfileMenu.tsx
··· 12 12 import {shareText, shareUrl} from '#/lib/sharing' 13 13 import {toShareUrl, toShareUrlBsky} from '#/lib/strings/url-helpers' 14 14 import {logger} from '#/logger' 15 - import {isWeb} from '#/platform/detection' 16 15 import {type Shadow} from '#/state/cache/types' 17 16 import {useModalControls} from '#/state/modals' 18 17 import { ··· 67 66 import {useFullVerificationState} from '#/components/verification' 68 67 import {VerificationCreatePrompt} from '#/components/verification/VerificationCreatePrompt' 69 68 import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt' 69 + import {IS_WEB} from '#/env' 70 70 import {Dot} from '#/features/nuxs/components/Dot' 71 71 import {Gradient} from '#/features/nuxs/components/Gradient' 72 72 import {useDevMode} from '#/storage/hooks/dev-mode' ··· 283 283 <Menu.Item 284 284 testID="profileHeaderDropdownShareBtn" 285 285 label={ 286 - isWeb ? _(msg`Copy link to profile`) : _(msg`Share via...`) 286 + IS_WEB ? _(msg`Copy link to profile`) : _(msg`Share via...`) 287 287 } 288 288 onPress={() => { 289 289 if (showLoggedOutWarning) { ··· 293 293 } 294 294 }}> 295 295 <Menu.ItemText> 296 - {isWeb ? ( 296 + {IS_WEB ? ( 297 297 <Trans>Copy link to profile</Trans> 298 298 ) : ( 299 299 <Trans>Share via...</Trans> 300 300 )} 301 301 </Menu.ItemText> 302 - <Menu.ItemIcon icon={isWeb ? ChainLinkIcon : ArrowOutOfBoxIcon} /> 302 + <Menu.ItemIcon 303 + icon={IS_WEB ? ChainLinkIcon : ArrowOutOfBoxIcon} 304 + /> 303 305 </Menu.Item> 304 306 <Menu.Item 305 307 testID="profileHeaderDropdownShareBtn" 306 308 label={ 307 - isWeb 309 + IS_WEB 308 310 ? _(msg`Copy via bsky.app`) 309 311 : _(msg`Share via bsky.app...`) 310 312 } ··· 316 318 } 317 319 }}> 318 320 <Menu.ItemText> 319 - {isWeb ? ( 321 + {IS_WEB ? ( 320 322 <Trans>Copy via bsky.app</Trans> 321 323 ) : ( 322 324 <Trans>Share via bsky.app...</Trans> 323 325 )} 324 326 </Menu.ItemText> 325 - <Menu.ItemIcon icon={isWeb ? ChainLinkIcon : ArrowOutOfBoxIcon} /> 327 + <Menu.ItemIcon icon={IS_WEB ? ChainLinkIcon : ArrowOutOfBoxIcon} /> 326 328 </Menu.Item> 327 329 <Menu.Item 328 330 testID="profileHeaderDropdownSearchBtn" ··· 453 455 a.flex_0, 454 456 { 455 457 color: t.palette.primary_500, 456 - right: isWeb ? -8 : -4, 458 + right: IS_WEB ? -8 : -4, 457 459 }, 458 460 ]}> 459 461 <Trans>New</Trans>
+4 -2
src/view/com/testing/TestCtrls.e2e.tsx
··· 1 1 import {useState} from 'react' 2 - import {LogBox, Pressable, View, TextInput} from 'react-native' 2 + import {LogBox, Pressable, TextInput, View} from 'react-native' 3 3 import {useQueryClient} from '@tanstack/react-query' 4 4 5 5 import {BLUESKY_PROXY_HEADER} from '#/lib/constants' 6 - import {useSessionApi, useAgent} from '#/state/session' 6 + import {useAgent, useSessionApi} from '#/state/session' 7 7 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 8 8 import {useOnboardingDispatch} from '#/state/shell/onboarding' 9 9 import {navigate} from '../../../Navigation' ··· 50 50 return ( 51 51 <View style={{position: 'absolute', top: 100, right: 0, zIndex: 100}}> 52 52 <TextInput 53 + accessibilityLabel="Text input field" 54 + accessibilityHint="Enter proxy header" 53 55 testID="e2eProxyHeaderInput" 54 56 onChangeText={val => setProxyHeader(val as any)} 55 57 onSubmitEditing={() => {
-2
src/view/com/util/Alert.web.tsx
··· 3 3 class WebAlert implements Pick<AlertStatic, 'alert'> { 4 4 public alert(title: string, message?: string, buttons?: AlertButton[]): void { 5 5 if (buttons === undefined || buttons.length === 0) { 6 - // eslint-disable-next-line no-alert 7 6 window.alert([title, message].filter(Boolean).join('\n')) 8 7 return 9 8 } 10 9 11 - // eslint-disable-next-line no-alert 12 10 const result = window.confirm([title, message].filter(Boolean).join('\n')) 13 11 14 12 if (result === true) {
+4 -4
src/view/com/util/Link.tsx
··· 25 25 linkRequiresWarning, 26 26 } from '#/lib/strings/url-helpers' 27 27 import {type TypographyVariant} from '#/lib/ThemeContext' 28 - import {isAndroid, isWeb} from '#/platform/detection' 29 28 import {emitSoftReset} from '#/state/events' 30 29 import {useModalControls} from '#/state/modals' 31 30 import {WebAuxClickWrapper} from '#/view/com/util/WebAuxClickWrapper' 32 31 import {useTheme} from '#/alf' 33 32 import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' 33 + import {IS_ANDROID, IS_WEB} from '#/env' 34 34 import {router} from '../../../routes' 35 35 import {PressableWithHover} from './PressableWithHover' 36 36 import {Text} from './text/Text' ··· 130 130 android_ripple={{ 131 131 color: t.atoms.bg_contrast_25.backgroundColor, 132 132 }} 133 - unstable_pressDelay={isAndroid ? 90 : undefined}> 133 + unstable_pressDelay={IS_ANDROID ? 90 : undefined}> 134 134 {/* @ts-ignore web only -prf */} 135 135 <View style={style} href={anchorHref}> 136 136 {children ? children : <Text>{title || 'link'}</Text>} ··· 219 219 }) 220 220 } 221 221 if ( 222 - isWeb && 222 + IS_WEB && 223 223 href !== '#' && 224 224 e != null && 225 225 isModifiedEvent(e as React.MouseEvent) ··· 323 323 onBeforePress, 324 324 ...props 325 325 }: TextLinkOnWebOnlyProps) { 326 - if (isWeb) { 326 + if (IS_WEB) { 327 327 return ( 328 328 <TextLink 329 329 testID={testID}
+3 -3
src/view/com/util/List.tsx
··· 11 11 import {useDedupe} from '#/lib/hooks/useDedupe' 12 12 import {useScrollHandlers} from '#/lib/ScrollContext' 13 13 import {addStyle} from '#/lib/styles' 14 - import {isIOS} from '#/platform/detection' 15 14 import {useLightbox} from '#/state/lightbox' 16 15 import {useTheme} from '#/alf' 16 + import {IS_IOS} from '#/env' 17 17 import {FlatList_INTERNAL} from './Views' 18 18 19 19 export type ListMethods = FlatList_INTERNAL ··· 94 94 } 95 95 } 96 96 97 - if (isIOS) { 97 + if (IS_IOS) { 98 98 runOnJS(dedupe)(updateActiveVideoViewAsync) 99 99 } 100 100 }, ··· 184 184 185 185 // We only want to use this context value on iOS because the `scrollsToTop` prop is iOS-only 186 186 // removing it saves us a re-render on Android 187 - const useAllowScrollToTop = isIOS ? useAllowScrollToTopIOS : () => undefined 187 + const useAllowScrollToTop = IS_IOS ? useAllowScrollToTopIOS : () => undefined 188 188 function useAllowScrollToTopIOS() { 189 189 const {activeLightbox} = useLightbox() 190 190 return !activeLightbox
+8 -8
src/view/com/util/MainScrollProvider.tsx
··· 9 9 import EventEmitter from 'eventemitter3' 10 10 11 11 import {ScrollProvider} from '#/lib/ScrollContext' 12 - import {isNative, isWeb} from '#/platform/detection' 13 12 import {useMinimalShellMode} from '#/state/shell' 14 13 import {useShellLayout} from '#/state/shell/shell-layout' 14 + import {IS_NATIVE, IS_WEB} from '#/env' 15 15 16 16 const WEB_HIDE_SHELL_THRESHOLD = 200 17 17 ··· 35 35 ) 36 36 37 37 useEffect(() => { 38 - if (isWeb) { 38 + if (IS_WEB) { 39 39 return listenToForcedWindowScroll(() => { 40 40 startDragOffset.set(null) 41 41 startMode.set(null) ··· 48 48 (e: NativeScrollEvent) => { 49 49 'worklet' 50 50 const offsetY = Math.max(0, e.contentOffset.y) 51 - if (isNative) { 51 + if (IS_NATIVE) { 52 52 const startDragOffsetValue = startDragOffset.get() 53 53 if (startDragOffsetValue === null) { 54 54 return ··· 75 75 (e: NativeScrollEvent) => { 76 76 'worklet' 77 77 const offsetY = Math.max(0, e.contentOffset.y) 78 - if (isNative) { 78 + if (IS_NATIVE) { 79 79 startDragOffset.set(offsetY) 80 80 startMode.set(headerMode.get()) 81 81 } ··· 86 86 const onEndDrag = useCallback( 87 87 (e: NativeScrollEvent) => { 88 88 'worklet' 89 - if (isNative) { 89 + if (IS_NATIVE) { 90 90 if (e.velocity && e.velocity.y !== 0) { 91 91 // If we detect a velocity, wait for onMomentumEnd to snap. 92 92 return ··· 100 100 const onMomentumEnd = useCallback( 101 101 (e: NativeScrollEvent) => { 102 102 'worklet' 103 - if (isNative) { 103 + if (IS_NATIVE) { 104 104 snapToClosestState(e) 105 105 } 106 106 }, ··· 111 111 (e: NativeScrollEvent) => { 112 112 'worklet' 113 113 const offsetY = Math.max(0, e.contentOffset.y) 114 - if (isNative) { 114 + if (IS_NATIVE) { 115 115 const startDragOffsetValue = startDragOffset.get() 116 116 const startModeValue = startMode.get() 117 117 if (startDragOffsetValue === null || startModeValue === null) { ··· 177 177 178 178 const emitter = new EventEmitter() 179 179 180 - if (isWeb) { 180 + if (IS_WEB) { 181 181 const originalScroll = window.scroll 182 182 window.scroll = function () { 183 183 emitter.emit('forced-scroll')
+4 -4
src/view/com/util/PostMeta.tsx
··· 12 12 import {sanitizeDisplayName} from '#/lib/strings/display-names' 13 13 import {sanitizeHandle} from '#/lib/strings/handles' 14 14 import {niceDate} from '#/lib/strings/time' 15 - import {isAndroid} from '#/platform/detection' 16 15 import {useProfileShadow} from '#/state/cache/profile-shadow' 17 16 import {precacheProfile} from '#/state/queries/profile' 18 17 import {atoms as a, platform, useTheme, web} from '#/alf' ··· 21 20 import {Text} from '#/components/Typography' 22 21 import {useSimpleVerificationState} from '#/components/verification' 23 22 import {VerificationCheck} from '#/components/verification/VerificationCheck' 23 + import {IS_ANDROID} from '#/env' 24 24 import {TimeElapsed} from './TimeElapsed' 25 25 import {PreviewableUserAvatar} from './UserAvatar' 26 26 ··· 60 60 return ( 61 61 <View 62 62 style={[ 63 - isAndroid ? a.flex_1 : a.flex_shrink, 63 + IS_ANDROID ? a.flex_1 : a.flex_shrink, 64 64 a.flex_row, 65 65 a.align_center, 66 66 a.pb_xs, ··· 152 152 a.pl_xs, 153 153 a.text_md, 154 154 a.leading_tight, 155 - isAndroid && a.flex_grow, 155 + IS_ANDROID && a.flex_grow, 156 156 a.text_right, 157 157 t.atoms.text_contrast_medium, 158 158 web({ 159 159 whiteSpace: 'nowrap', 160 160 }), 161 161 ]}> 162 - {!isAndroid && ( 162 + {!IS_ANDROID && ( 163 163 <Text 164 164 style={[ 165 165 a.text_md,
+7 -8
src/view/com/util/UserAvatar.tsx
··· 16 16 import {useQueryClient} from '@tanstack/react-query' 17 17 18 18 import {useActorStatus} from '#/lib/actor-status' 19 - import {isTouchDevice} from '#/lib/browser' 20 19 import {useHaptics} from '#/lib/haptics' 21 20 import { 22 21 useCameraPermission, ··· 30 29 import {isCancelledError} from '#/lib/strings/errors' 31 30 import {sanitizeHandle} from '#/lib/strings/handles' 32 31 import {logger} from '#/logger' 33 - import {isAndroid, isNative, isWeb} from '#/platform/detection' 34 32 import { 35 33 type ComposerImage, 36 34 compressImage, ··· 59 57 import {MediaInsetBorder} from '#/components/MediaInsetBorder' 60 58 import * as Menu from '#/components/Menu' 61 59 import {ProfileHoverCard} from '#/components/ProfileHoverCard' 60 + import {IS_ANDROID, IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env' 62 61 import type * as bsky from '#/types/bsky' 63 62 64 63 export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler' ··· 93 92 onBeforePress?: () => void 94 93 } 95 94 96 - const BLUR_AMOUNT = isWeb ? 5 : 100 95 + const BLUR_AMOUNT = IS_WEB ? 5 : 100 97 96 98 97 let DefaultAvatar = ({ 99 98 type, ··· 311 310 }, [size, style]) 312 311 313 312 return avatar && 314 - !((moderation?.blur && isAndroid) /* android crashes with blur */) ? ( 313 + !((moderation?.blur && IS_ANDROID) /* android crashes with blur */) ? ( 315 314 <View style={containerStyle}> 316 315 {usePlainRNImage ? ( 317 316 <RNImage ··· 428 427 } 429 428 430 429 try { 431 - if (isNative) { 430 + if (IS_NATIVE) { 432 431 onSelectNewAvatar( 433 432 await compressIfNeeded( 434 433 await openCropper({ ··· 500 499 </Menu.Trigger> 501 500 <Menu.Outer showCancel> 502 501 <Menu.Group> 503 - {isNative && ( 502 + {IS_NATIVE && ( 504 503 <Menu.Item 505 504 testID="changeAvatarCameraBtn" 506 505 label={_(msg`Upload from Camera`)} ··· 517 516 label={_(msg`Upload from Library`)} 518 517 onPress={onOpenLibrary}> 519 518 <Menu.ItemText> 520 - {isNative ? ( 519 + {IS_NATIVE ? ( 521 520 <Trans>Upload from Library</Trans> 522 521 ) : ( 523 522 <Trans>Upload from Files</Trans> ··· 607 606 <ProfileHoverCard did={profile.did} disable={disableHoverCard}> 608 607 {disableNavigation ? ( 609 608 avatarEl 610 - ) : status.isActive && (isNative || isTouchDevice) ? ( 609 + ) : status.isActive && (IS_NATIVE || IS_WEB_TOUCH_DEVICE) ? ( 611 610 <> 612 611 <Button 613 612 label={_(
+5 -5
src/view/com/util/UserBanner.tsx
··· 14 14 import {type PickerImage} from '#/lib/media/picker.shared' 15 15 import {isCancelledError} from '#/lib/strings/errors' 16 16 import {logger} from '#/logger' 17 - import {isAndroid, isNative} from '#/platform/detection' 18 17 import { 19 18 type ComposerImage, 20 19 compressImage, ··· 36 35 import {StreamingLive_Stroke2_Corner0_Rounded as LibraryIcon} from '#/components/icons/StreamingLive' 37 36 import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' 38 37 import * as Menu from '#/components/Menu' 38 + import {IS_ANDROID, IS_NATIVE} from '#/env' 39 39 40 40 export function UserBanner({ 41 41 type, ··· 80 80 } 81 81 82 82 try { 83 - if (isNative) { 83 + if (IS_NATIVE) { 84 84 onSelectNewBanner?.( 85 85 await compressIfNeeded( 86 86 await openCropper({ ··· 163 163 </Menu.Trigger> 164 164 <Menu.Outer showCancel> 165 165 <Menu.Group> 166 - {isNative && ( 166 + {IS_NATIVE && ( 167 167 <Menu.Item 168 168 testID="changeBannerCameraBtn" 169 169 label={_(msg`Upload from Camera`)} ··· 180 180 label={_(msg`Upload from Library`)} 181 181 onPress={onOpenLibrary}> 182 182 <Menu.ItemText> 183 - {isNative ? ( 183 + {IS_NATIVE ? ( 184 184 <Trans>Upload from Library</Trans> 185 185 ) : ( 186 186 <Trans>Upload from Files</Trans> ··· 217 217 /> 218 218 </> 219 219 ) : banner && 220 - !((moderation?.blur && isAndroid) /* android crashes with blur */) ? ( 220 + !((moderation?.blur && IS_ANDROID) /* android crashes with blur */) ? ( 221 221 <Image 222 222 testID="userBannerImage" 223 223 style={[styles.bannerImage, t.atoms.bg_contrast_25]}
+2 -2
src/view/com/util/ViewSelector.tsx
··· 13 13 import {usePalette} from '#/lib/hooks/usePalette' 14 14 import {clamp} from '#/lib/numbers' 15 15 import {colors, s} from '#/lib/styles' 16 - import {isAndroid} from '#/platform/detection' 16 + import {IS_ANDROID} from '#/env' 17 17 import {Text} from './text/Text' 18 18 import {FlatList_INTERNAL} from './Views' 19 19 ··· 120 120 renderItem={renderItemInternal} 121 121 ListFooterComponent={ListFooterComponent} 122 122 // NOTE sticky header disabled on android due to major performance issues -prf 123 - stickyHeaderIndices={isAndroid ? undefined : STICKY_HEADER_INDICES} 123 + stickyHeaderIndices={IS_ANDROID ? undefined : STICKY_HEADER_INDICES} 124 124 onScroll={onScroll} 125 125 onEndReached={onEndReached} 126 126 refreshControl={
+2 -2
src/view/com/util/fab/FABInner.tsx
··· 12 12 import {useHaptics} from '#/lib/haptics' 13 13 import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform' 14 14 import {clamp} from '#/lib/numbers' 15 - import {isWeb} from '#/platform/detection' 16 15 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 17 16 import {ios, useBreakpoints, useTheme} from '#/alf' 18 17 import {atoms as a} from '#/alf' 18 + import {IS_WEB} from '#/env' 19 19 20 20 export interface FABProps extends ComponentProps<typeof Pressable> { 21 21 testID?: string ··· 97 97 }, 98 98 outer: { 99 99 // @ts-ignore web-only 100 - position: isWeb ? 'fixed' : 'absolute', 100 + position: IS_WEB ? 'fixed' : 'absolute', 101 101 zIndex: 1, 102 102 cursor: 'pointer', 103 103 },
+2 -2
src/view/com/util/forms/Button.tsx
··· 153 153 async (event: GestureResponderEvent) => { 154 154 event.stopPropagation() 155 155 event.preventDefault() 156 - withLoading && setIsLoading(true) 156 + if (withLoading) setIsLoading(true) 157 157 await onPress?.(event) 158 - withLoading && setIsLoading(false) 158 + if (withLoading) setIsLoading(false) 159 159 }, 160 160 [onPress, withLoading], 161 161 )
+2 -2
src/view/com/util/layouts/LoggedOutLayout.tsx
··· 5 5 import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible' 6 6 import {usePalette} from '#/lib/hooks/usePalette' 7 7 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 8 - import {isWeb} from '#/platform/detection' 9 8 import {atoms as a} from '#/alf' 9 + import {IS_WEB} from '#/env' 10 10 import {Text} from '../text/Text' 11 11 12 12 export const LoggedOutLayout = ({ ··· 79 79 contentContainerStyle={styles.scrollViewContentContainer} 80 80 keyboardShouldPersistTaps="handled" 81 81 keyboardDismissMode="on-drag"> 82 - <View style={[styles.contentWrapper, isWeb && a.my_auto]}> 82 + <View style={[styles.contentWrapper, IS_WEB && a.my_auto]}> 83 83 {children} 84 84 </View> 85 85 </ScrollView>
+4 -3
src/view/com/util/text/Text.tsx
··· 5 5 import {lh, s} from '#/lib/styles' 6 6 import {type TypographyVariant, useTheme} from '#/lib/ThemeContext' 7 7 import {logger} from '#/logger' 8 - import {isIOS, isWeb} from '#/platform/detection' 9 8 import {applyFonts, useAlf} from '#/alf' 10 9 import { 11 10 childHasEmoji, 12 11 renderChildrenWithEmoji, 13 12 type StringChild, 14 13 } from '#/alf/typography' 14 + import {IS_IOS, IS_WEB} from '#/env' 15 15 16 16 export type CustomTextProps = Omit<TextProps, 'children'> & { 17 17 type?: TypographyVariant ··· 51 51 if (__DEV__) { 52 52 if (!emoji && childHasEmoji(children)) { 53 53 logger.warn( 54 + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string 54 55 `Text: emoji detected but emoji not enabled: "${children}"\n\nPlease add <Text emoji />'`, 55 56 ) 56 57 } ··· 80 81 } 81 82 82 83 return { 83 - uiTextView: selectable && isIOS, 84 + uiTextView: selectable && IS_IOS, 84 85 selectable, 85 86 style: flattened, 86 - dataSet: isWeb 87 + dataSet: IS_WEB 87 88 ? Object.assign({tooltip: title}, dataSet || {}) 88 89 : undefined, 89 90 ...props,
+4 -4
src/view/screens/Feeds.tsx
··· 16 16 } from '#/lib/routes/types' 17 17 import {cleanError} from '#/lib/strings/errors' 18 18 import {s} from '#/lib/styles' 19 - import {isNative, isWeb} from '#/platform/detection' 20 19 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 21 20 import { 22 21 type SavedFeedItem, ··· 47 46 import * as Layout from '#/components/Layout' 48 47 import {Link} from '#/components/Link' 49 48 import * as ListCard from '#/components/ListCard' 49 + import {IS_NATIVE, IS_WEB} from '#/env' 50 50 51 51 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Feeds'> 52 52 ··· 388 388 const onChangeSearchFocus = React.useCallback( 389 389 (focus: boolean) => { 390 390 if (focus && searchBarIndex > -1) { 391 - if (isNative) { 391 + if (IS_NATIVE) { 392 392 // scrollToIndex scrolls the exact right amount, so use if available 393 393 listRef.current?.scrollToIndex({ 394 394 index: searchBarIndex, ··· 684 684 return ( 685 685 <View 686 686 style={ 687 - isWeb 687 + IS_WEB 688 688 ? [ 689 689 a.flex_row, 690 690 a.px_md, ··· 720 720 return ( 721 721 <View 722 722 style={ 723 - isWeb 723 + IS_WEB 724 724 ? [a.flex_row, a.px_md, a.pt_lg, a.pb_lg, a.gap_md] 725 725 : [{flexDirection: 'row-reverse'}, a.p_lg, a.gap_md] 726 726 }>
+2 -2
src/view/screens/Home.tsx
··· 12 12 type NativeStackScreenProps, 13 13 } from '#/lib/routes/types' 14 14 import {logEvent} from '#/lib/statsig/statsig' 15 - import {isWeb} from '#/platform/detection' 16 15 import {emitSoftReset} from '#/state/events' 17 16 import { 18 17 type SavedFeedSourceInfo, ··· 37 36 import {FollowingEndOfFeed} from '#/view/com/posts/FollowingEndOfFeed' 38 37 import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned' 39 38 import * as Layout from '#/components/Layout' 39 + import {IS_WEB} from '#/env' 40 40 import {useDemoMode} from '#/storage/hooks/demo-mode' 41 41 42 42 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'> ··· 48 48 usePinnedFeedsInfos() 49 49 50 50 React.useEffect(() => { 51 - if (isWeb && !currentAccount) { 51 + if (IS_WEB && !currentAccount) { 52 52 const getParams = new URLSearchParams(window.location.search) 53 53 const splash = getParams.get('splash') 54 54 if (splash === 'true') {
+3 -3
src/view/screens/Notifications.tsx
··· 14 14 } from '#/lib/routes/types' 15 15 import {s} from '#/lib/styles' 16 16 import {logger} from '#/logger' 17 - import {isNative} from '#/platform/detection' 18 17 import {emitSoftReset, listenSoftReset} from '#/state/events' 19 18 import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 20 19 import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed' ··· 40 39 import * as Layout from '#/components/Layout' 41 40 import {InlineLinkText, Link} from '#/components/Link' 42 41 import {Loader} from '#/components/Loader' 42 + import {IS_NATIVE} from '#/env' 43 43 44 44 // We don't currently persist this across reloads since 45 45 // you gotta visit All to clear the badge anyway. ··· 200 200 // event handlers 201 201 // = 202 202 const scrollToTop = useCallback(() => { 203 - scrollElRef.current?.scrollToOffset({animated: isNative, offset: 0}) 203 + scrollElRef.current?.scrollToOffset({animated: IS_NATIVE, offset: 0}) 204 204 setMinimalShellMode(false) 205 205 }, [scrollElRef, setMinimalShellMode]) 206 206 ··· 230 230 // on focus, check for latest, but only invalidate if the user 231 231 // isnt scrolled down to avoid moving content underneath them 232 232 let currentIsScrolledDown 233 - if (isNative) { 233 + if (IS_NATIVE) { 234 234 currentIsScrolledDown = isScrolledDown 235 235 } else { 236 236 // On the web, this isn't always updated in time so
+2 -2
src/view/shell/Drawer.tsx
··· 13 13 import {type NavigationProp} from '#/lib/routes/types' 14 14 import {sanitizeHandle} from '#/lib/strings/handles' 15 15 import {colors} from '#/lib/styles' 16 - import {isWeb} from '#/platform/detection' 17 16 import {emitSoftReset} from '#/state/events' 18 17 import {useDisableFollowersMetrics} from '#/state/preferences/disable-followers-metrics' 19 18 import {useDisableFollowingMetrics} from '#/state/preferences/disable-following-metrics' ··· 58 57 import {Text} from '#/components/Typography' 59 58 import {useSimpleVerificationState} from '#/components/verification' 60 59 import {VerificationCheck} from '#/components/verification/VerificationCheck' 60 + import {IS_WEB} from '#/env' 61 61 62 62 const iconWidth = 26 63 63 ··· 183 183 (tab: 'Home' | 'Search' | 'Messages' | 'Notifications' | 'MyProfile') => { 184 184 const state = navigation.getState() 185 185 setDrawerOpen(false) 186 - if (isWeb) { 186 + if (IS_WEB) { 187 187 // hack because we have flat navigator for web and MyProfile does not exist on the web navigator -ansh 188 188 if (tab === 'MyProfile') { 189 189 navigation.navigate('Profile', {name: currentAccount!.handle})
+3 -3
src/view/shell/createNativeStackNavigatorWithAuth.tsx
··· 27 27 28 28 import {PWI_ENABLED} from '#/lib/build-flags' 29 29 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 30 - import {isNative, isWeb} from '#/platform/detection' 31 30 import {useSession} from '#/state/session' 32 31 import {useOnboardingState} from '#/state/shell' 33 32 import { ··· 39 38 import {SignupQueued} from '#/screens/SignupQueued' 40 39 import {atoms as a, useLayoutBreakpoints} from '#/alf' 41 40 import {PolicyUpdateOverlay} from '#/components/PolicyUpdateOverlay' 41 + import {IS_NATIVE, IS_WEB} from '#/env' 42 42 import {BottomBarWeb} from './bottom-bar/BottomBarWeb' 43 43 import {DesktopLeftNav} from './desktop/LeftNav' 44 44 import {DesktopRightNav} from './desktop/RightNav' ··· 115 115 const {setShowLoggedOut} = useLoggedOutViewControls() 116 116 const {isMobile} = useWebMediaQueries() 117 117 const {leftNavMinimal} = useLayoutBreakpoints() 118 - if (!hasSession && (!PWI_ENABLED || activeRouteRequiresAuth || isNative)) { 118 + if (!hasSession && (!PWI_ENABLED || activeRouteRequiresAuth || IS_NATIVE)) { 119 119 return <LoggedOut /> 120 120 } 121 121 if (hasSession && currentAccount?.signupQueued) { ··· 158 158 describe={describe} 159 159 /> 160 160 </View> 161 - {isWeb && ( 161 + {IS_WEB && ( 162 162 <> 163 163 {showBottomBar ? <BottomBarWeb /> : <DesktopLeftNav />} 164 164 {!isMobile && <DesktopRightNav routeName={activeRoute.name} />}
+8 -6
src/view/shell/index.tsx
··· 11 11 import {useNotificationsHandler} from '#/lib/hooks/useNotificationHandler' 12 12 import {useNotificationsRegistration} from '#/lib/notifications/notifications' 13 13 import {isStateAtTabRoot} from '#/lib/routes/helpers' 14 - import {isAndroid, isIOS} from '#/platform/detection' 15 14 import {useDialogFullyExpandedCountContext} from '#/state/dialogs' 16 15 import {useSession} from '#/state/session' 17 16 import { ··· 43 42 import {useAgeAssurance} from '#/ageAssurance' 44 43 import {NoAccessScreen} from '#/ageAssurance/components/NoAccessScreen' 45 44 import {RedirectOverlay} from '#/ageAssurance/components/RedirectOverlay' 45 + import {IS_ANDROID, IS_IOS} from '#/env' 46 46 import {RoutesContainer, TabsNavigator} from '#/Navigation' 47 47 import {BottomSheetOutlet} from '../../../modules/bottom-sheet' 48 48 import {updateActiveViewAsync} from '../../../modules/expo-bluesky-swiss-army/src/VisibilityView' ··· 60 60 useNotificationsHandler() 61 61 62 62 useEffect(() => { 63 - if (isAndroid) { 63 + if (IS_ANDROID) { 64 64 const listener = BackHandler.addEventListener('hardwareBackPress', () => { 65 65 return closeAnyActiveElement() 66 66 }) ··· 80 80 const navigation = useNavigation() 81 81 const dedupe = useDedupe(1000) 82 82 useEffect(() => { 83 - if (!isAndroid) return 83 + if (!IS_ANDROID) return 84 84 const onFocusOrBlur = () => { 85 85 setTimeout(() => { 86 86 dedupe(updateActiveViewAsync) ··· 190 190 swipeEdgeWidth={winDim.width} 191 191 swipeMinVelocity={100} 192 192 swipeMinDistance={10} 193 - drawerType={isIOS ? 'slide' : 'front'} 193 + drawerType={IS_IOS ? 'slide' : 'front'} 194 194 overlayStyle={{ 195 195 backgroundColor: select(t.name, { 196 196 light: 'rgba(0, 57, 117, 0.1)', 197 - dark: isAndroid ? 'rgba(16, 133, 254, 0.1)' : 'rgba(1, 82, 168, 0.1)', 197 + dark: IS_ANDROID 198 + ? 'rgba(16, 133, 254, 0.1)' 199 + : 'rgba(1, 82, 168, 0.1)', 198 200 dim: 'rgba(10, 13, 16, 0.8)', 199 201 }), 200 202 }}> ··· 220 222 <SystemBars 221 223 style={{ 222 224 statusBar: 223 - t.name !== 'light' || (isIOS && fullyExpandedCount > 0) 225 + t.name !== 'light' || (IS_IOS && fullyExpandedCount > 0) 224 226 ? 'light' 225 227 : 'dark', 226 228 navigationBar: t.name !== 'light' ? 'light' : 'dark',
+826 -250
yarn.lock
··· 3788 3788 dependencies: 3789 3789 "@types/hammerjs" "^2.0.36" 3790 3790 3791 + "@emnapi/core@^1.4.3": 3792 + version "1.8.1" 3793 + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.8.1.tgz#fd9efe721a616288345ffee17a1f26ac5dd01349" 3794 + integrity sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg== 3795 + dependencies: 3796 + "@emnapi/wasi-threads" "1.1.0" 3797 + tslib "^2.4.0" 3798 + 3791 3799 "@emnapi/runtime@^1.2.0": 3792 3800 version "1.3.1" 3793 3801 resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.3.1.tgz#0fcaa575afc31f455fd33534c19381cfce6c6f60" 3794 3802 integrity sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw== 3803 + dependencies: 3804 + tslib "^2.4.0" 3805 + 3806 + "@emnapi/runtime@^1.4.3": 3807 + version "1.8.1" 3808 + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.8.1.tgz#550fa7e3c0d49c5fb175a116e8cd70614f9a22a5" 3809 + integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg== 3810 + dependencies: 3811 + tslib "^2.4.0" 3812 + 3813 + "@emnapi/wasi-threads@1.1.0": 3814 + version "1.1.0" 3815 + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" 3816 + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== 3795 3817 dependencies: 3796 3818 tslib "^2.4.0" 3797 3819 ··· 3924 3946 dependencies: 3925 3947 eslint-visitor-keys "^3.4.3" 3926 3948 3949 + "@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": 3950 + version "4.9.1" 3951 + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" 3952 + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== 3953 + dependencies: 3954 + eslint-visitor-keys "^3.4.3" 3955 + 3927 3956 "@eslint-community/regexpp@^4.10.0": 3928 3957 version "4.12.1" 3929 3958 resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" 3930 3959 integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== 3931 3960 3932 - "@eslint-community/regexpp@^4.6.1": 3933 - version "4.6.2" 3934 - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" 3935 - integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== 3961 + "@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2": 3962 + version "4.12.2" 3963 + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" 3964 + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== 3936 3965 3937 - "@eslint/eslintrc@^2.1.2": 3938 - version "2.1.2" 3939 - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" 3940 - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== 3966 + "@eslint/config-array@^0.21.1": 3967 + version "0.21.1" 3968 + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713" 3969 + integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== 3970 + dependencies: 3971 + "@eslint/object-schema" "^2.1.7" 3972 + debug "^4.3.1" 3973 + minimatch "^3.1.2" 3974 + 3975 + "@eslint/config-helpers@^0.4.2": 3976 + version "0.4.2" 3977 + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" 3978 + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== 3979 + dependencies: 3980 + "@eslint/core" "^0.17.0" 3981 + 3982 + "@eslint/core@^0.17.0": 3983 + version "0.17.0" 3984 + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" 3985 + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== 3986 + dependencies: 3987 + "@types/json-schema" "^7.0.15" 3988 + 3989 + "@eslint/eslintrc@^3.3.1": 3990 + version "3.3.3" 3991 + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.3.tgz#26393a0806501b5e2b6a43aa588a4d8df67880ac" 3992 + integrity sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ== 3941 3993 dependencies: 3942 3994 ajv "^6.12.4" 3943 3995 debug "^4.3.2" 3944 - espree "^9.6.0" 3945 - globals "^13.19.0" 3996 + espree "^10.0.1" 3997 + globals "^14.0.0" 3946 3998 ignore "^5.2.0" 3947 3999 import-fresh "^3.2.1" 3948 - js-yaml "^4.1.0" 4000 + js-yaml "^4.1.1" 3949 4001 minimatch "^3.1.2" 3950 4002 strip-json-comments "^3.1.1" 3951 4003 3952 - "@eslint/js@^8.47.0": 3953 - version "8.47.0" 3954 - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d" 3955 - integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og== 4004 + "@eslint/js@9.39.2", "@eslint/js@^9.39.2": 4005 + version "9.39.2" 4006 + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.2.tgz#2d4b8ec4c3ea13c1b3748e0c97ecd766bdd80599" 4007 + integrity sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA== 4008 + 4009 + "@eslint/object-schema@^2.1.7": 4010 + version "2.1.7" 4011 + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" 4012 + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== 4013 + 4014 + "@eslint/plugin-kit@^0.4.1": 4015 + version "0.4.1" 4016 + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" 4017 + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== 4018 + dependencies: 4019 + "@eslint/core" "^0.17.0" 4020 + levn "^0.4.1" 3956 4021 3957 4022 "@expo/cli@54.0.18": 3958 4023 version "54.0.18" ··· 4675 4740 resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-11.0.4.tgz#42a7f244fd3dd777792bfb74b8c6340ae9182f37" 4676 4741 integrity sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ== 4677 4742 4678 - "@humanwhocodes/config-array@^0.11.10": 4679 - version "0.11.10" 4680 - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" 4681 - integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== 4743 + "@humanfs/core@^0.19.1": 4744 + version "0.19.1" 4745 + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" 4746 + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== 4747 + 4748 + "@humanfs/node@^0.16.6": 4749 + version "0.16.7" 4750 + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.7.tgz#822cb7b3a12c5a240a24f621b5a2413e27a45f26" 4751 + integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== 4682 4752 dependencies: 4683 - "@humanwhocodes/object-schema" "^1.2.1" 4684 - debug "^4.1.1" 4685 - minimatch "^3.0.5" 4753 + "@humanfs/core" "^0.19.1" 4754 + "@humanwhocodes/retry" "^0.4.0" 4686 4755 4687 4756 "@humanwhocodes/module-importer@^1.0.1": 4688 4757 version "1.0.1" 4689 4758 resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" 4690 4759 integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== 4691 4760 4692 - "@humanwhocodes/object-schema@^1.2.1": 4693 - version "1.2.1" 4694 - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" 4695 - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== 4761 + "@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": 4762 + version "0.4.3" 4763 + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" 4764 + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== 4696 4765 4697 4766 "@ide/backoff@^1.0.0": 4698 4767 version "1.0.0" ··· 5393 5462 "@expo/image-utils" "^0.8.7" 5394 5463 xcode "^3.0.1" 5395 5464 5465 + "@napi-rs/wasm-runtime@^0.2.11": 5466 + version "0.2.12" 5467 + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" 5468 + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== 5469 + dependencies: 5470 + "@emnapi/core" "^1.4.3" 5471 + "@emnapi/runtime" "^1.4.3" 5472 + "@tybys/wasm-util" "^0.10.0" 5473 + 5396 5474 "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": 5397 5475 version "5.1.1-v1" 5398 5476 resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" ··· 5430 5508 resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 5431 5509 integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 5432 5510 5433 - "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": 5511 + "@nodelib/fs.walk@^1.2.3": 5434 5512 version "1.2.8" 5435 5513 resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 5436 5514 integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== ··· 6419 6497 resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-3.0.0.tgz#96fdb89d25c62e7b6a5d08caf0ce5114370e3b8f" 6420 6498 integrity sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg== 6421 6499 6422 - "@rtsao/scc@^1.1.0": 6423 - version "1.1.0" 6424 - resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" 6425 - integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== 6426 - 6427 6500 "@sentry-internal/browser-utils@8.55.0": 6428 6501 version "8.55.0" 6429 6502 resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.55.0.tgz#d89bae423edd29c39f01285c8e2d59ce9289d9a6" ··· 7369 7442 resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" 7370 7443 integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== 7371 7444 7445 + "@tybys/wasm-util@^0.10.0": 7446 + version "0.10.1" 7447 + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" 7448 + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== 7449 + dependencies: 7450 + tslib "^2.4.0" 7451 + 7372 7452 "@types/babel__core@^7.1.14": 7373 7453 version "7.20.1" 7374 7454 resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" ··· 7477 7557 resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" 7478 7558 integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== 7479 7559 7560 + "@types/estree@^1.0.6": 7561 + version "1.0.8" 7562 + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" 7563 + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== 7564 + 7480 7565 "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": 7481 7566 version "4.17.35" 7482 7567 resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" ··· 7595 7680 resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" 7596 7681 integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== 7597 7682 7598 - "@types/json5@^0.0.29": 7599 - version "0.0.29" 7600 - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" 7601 - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== 7683 + "@types/json-schema@^7.0.15": 7684 + version "7.0.15" 7685 + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" 7686 + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== 7602 7687 7603 7688 "@types/lodash.chunk@^4.2.7": 7604 7689 version "4.2.7" ··· 7774 7859 dependencies: 7775 7860 "@types/yargs-parser" "*" 7776 7861 7777 - "@typescript-eslint/eslint-plugin@^7.1.1", "@typescript-eslint/eslint-plugin@^7.18.0": 7862 + "@typescript-eslint/eslint-plugin@8.53.0": 7863 + version "8.53.0" 7864 + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz#afb966c66a2fdc6158cf81118204a971a36d0fc5" 7865 + integrity sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg== 7866 + dependencies: 7867 + "@eslint-community/regexpp" "^4.12.2" 7868 + "@typescript-eslint/scope-manager" "8.53.0" 7869 + "@typescript-eslint/type-utils" "8.53.0" 7870 + "@typescript-eslint/utils" "8.53.0" 7871 + "@typescript-eslint/visitor-keys" "8.53.0" 7872 + ignore "^7.0.5" 7873 + natural-compare "^1.4.0" 7874 + ts-api-utils "^2.4.0" 7875 + 7876 + "@typescript-eslint/eslint-plugin@^7.1.1": 7778 7877 version "7.18.0" 7779 7878 resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3" 7780 7879 integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== ··· 7789 7888 natural-compare "^1.4.0" 7790 7889 ts-api-utils "^1.3.0" 7791 7890 7792 - "@typescript-eslint/parser@^7.1.1", "@typescript-eslint/parser@^7.18.0": 7891 + "@typescript-eslint/parser@8.53.0": 7892 + version "8.53.0" 7893 + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.53.0.tgz#d8bed6f12dc74e03751e5f947510ff2b165990c6" 7894 + integrity sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg== 7895 + dependencies: 7896 + "@typescript-eslint/scope-manager" "8.53.0" 7897 + "@typescript-eslint/types" "8.53.0" 7898 + "@typescript-eslint/typescript-estree" "8.53.0" 7899 + "@typescript-eslint/visitor-keys" "8.53.0" 7900 + debug "^4.4.3" 7901 + 7902 + "@typescript-eslint/parser@^7.1.1": 7793 7903 version "7.18.0" 7794 7904 resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.18.0.tgz#83928d0f1b7f4afa974098c64b5ce6f9051f96a0" 7795 7905 integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== ··· 7800 7910 "@typescript-eslint/visitor-keys" "7.18.0" 7801 7911 debug "^4.3.4" 7802 7912 7913 + "@typescript-eslint/project-service@8.53.0": 7914 + version "8.53.0" 7915 + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.53.0.tgz#327c67c61c16a1c8b12a440b0779b41eb77cc7df" 7916 + integrity sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg== 7917 + dependencies: 7918 + "@typescript-eslint/tsconfig-utils" "^8.53.0" 7919 + "@typescript-eslint/types" "^8.53.0" 7920 + debug "^4.4.3" 7921 + 7803 7922 "@typescript-eslint/scope-manager@5.62.0": 7804 7923 version "5.62.0" 7805 7924 resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" ··· 7816 7935 "@typescript-eslint/types" "7.18.0" 7817 7936 "@typescript-eslint/visitor-keys" "7.18.0" 7818 7937 7938 + "@typescript-eslint/scope-manager@8.53.0": 7939 + version "8.53.0" 7940 + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.53.0.tgz#f922fcbf0d42e72f065297af31779ccf19de9a97" 7941 + integrity sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g== 7942 + dependencies: 7943 + "@typescript-eslint/types" "8.53.0" 7944 + "@typescript-eslint/visitor-keys" "8.53.0" 7945 + 7946 + "@typescript-eslint/tsconfig-utils@8.53.0", "@typescript-eslint/tsconfig-utils@^8.53.0": 7947 + version "8.53.0" 7948 + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.0.tgz#105279d7969a7abdc8345cc9c57cff83cf910f8f" 7949 + integrity sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA== 7950 + 7819 7951 "@typescript-eslint/type-utils@7.18.0": 7820 7952 version "7.18.0" 7821 7953 resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b" ··· 7826 7958 debug "^4.3.4" 7827 7959 ts-api-utils "^1.3.0" 7828 7960 7961 + "@typescript-eslint/type-utils@8.53.0": 7962 + version "8.53.0" 7963 + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.53.0.tgz#81a0de5c01fc68f6df0591d03cd8226bda01c91f" 7964 + integrity sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw== 7965 + dependencies: 7966 + "@typescript-eslint/types" "8.53.0" 7967 + "@typescript-eslint/typescript-estree" "8.53.0" 7968 + "@typescript-eslint/utils" "8.53.0" 7969 + debug "^4.4.3" 7970 + ts-api-utils "^2.4.0" 7971 + 7829 7972 "@typescript-eslint/types@5.62.0": 7830 7973 version "5.62.0" 7831 7974 resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" ··· 7836 7979 resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" 7837 7980 integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== 7838 7981 7982 + "@typescript-eslint/types@8.53.0", "@typescript-eslint/types@^8.35.0", "@typescript-eslint/types@^8.53.0": 7983 + version "8.53.0" 7984 + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.53.0.tgz#1adcad3fa32bc2c4cbf3785ba07a5e3151819efb" 7985 + integrity sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ== 7986 + 7839 7987 "@typescript-eslint/typescript-estree@5.62.0": 7840 7988 version "5.62.0" 7841 7989 resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" ··· 7863 8011 semver "^7.6.0" 7864 8012 ts-api-utils "^1.3.0" 7865 8013 8014 + "@typescript-eslint/typescript-estree@8.53.0": 8015 + version "8.53.0" 8016 + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.0.tgz#7805b46b7a8ce97e91b7bb56fc8b1ba26ca8ef52" 8017 + integrity sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw== 8018 + dependencies: 8019 + "@typescript-eslint/project-service" "8.53.0" 8020 + "@typescript-eslint/tsconfig-utils" "8.53.0" 8021 + "@typescript-eslint/types" "8.53.0" 8022 + "@typescript-eslint/visitor-keys" "8.53.0" 8023 + debug "^4.4.3" 8024 + minimatch "^9.0.5" 8025 + semver "^7.7.3" 8026 + tinyglobby "^0.2.15" 8027 + ts-api-utils "^2.4.0" 8028 + 7866 8029 "@typescript-eslint/utils@7.18.0": 7867 8030 version "7.18.0" 7868 8031 resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" ··· 7873 8036 "@typescript-eslint/types" "7.18.0" 7874 8037 "@typescript-eslint/typescript-estree" "7.18.0" 7875 8038 7876 - "@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.61.0": 8039 + "@typescript-eslint/utils@8.53.0", "@typescript-eslint/utils@^8.0.0": 8040 + version "8.53.0" 8041 + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.53.0.tgz#bf0a4e2edaf1afc9abce209fc02f8cab0b74af13" 8042 + integrity sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA== 8043 + dependencies: 8044 + "@eslint-community/eslint-utils" "^4.9.1" 8045 + "@typescript-eslint/scope-manager" "8.53.0" 8046 + "@typescript-eslint/types" "8.53.0" 8047 + "@typescript-eslint/typescript-estree" "8.53.0" 8048 + 8049 + "@typescript-eslint/utils@^5.10.0": 7877 8050 version "5.62.0" 7878 8051 resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" 7879 8052 integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== ··· 7903 8076 "@typescript-eslint/types" "7.18.0" 7904 8077 eslint-visitor-keys "^3.4.3" 7905 8078 8079 + "@typescript-eslint/visitor-keys@8.53.0": 8080 + version "8.53.0" 8081 + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.0.tgz#9a785664ddae7e3f7e570ad8166e48dbc9c6cf02" 8082 + integrity sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw== 8083 + dependencies: 8084 + "@typescript-eslint/types" "8.53.0" 8085 + eslint-visitor-keys "^4.2.1" 8086 + 7906 8087 "@ungap/structured-clone@^1.3.0": 7907 8088 version "1.3.0" 7908 8089 resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" 7909 8090 integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== 7910 8091 8092 + "@unrs/resolver-binding-android-arm-eabi@1.11.1": 8093 + version "1.11.1" 8094 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz#9f5b04503088e6a354295e8ea8fe3cb99e43af81" 8095 + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== 8096 + 8097 + "@unrs/resolver-binding-android-arm64@1.11.1": 8098 + version "1.11.1" 8099 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz#7414885431bd7178b989aedc4d25cccb3865bc9f" 8100 + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== 8101 + 8102 + "@unrs/resolver-binding-darwin-arm64@1.11.1": 8103 + version "1.11.1" 8104 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf" 8105 + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== 8106 + 8107 + "@unrs/resolver-binding-darwin-x64@1.11.1": 8108 + version "1.11.1" 8109 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz#fd4d81257b13f4d1a083890a6a17c00de571f0dc" 8110 + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== 8111 + 8112 + "@unrs/resolver-binding-freebsd-x64@1.11.1": 8113 + version "1.11.1" 8114 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz#d2513084d0f37c407757e22f32bd924a78cfd99b" 8115 + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== 8116 + 8117 + "@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": 8118 + version "1.11.1" 8119 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz#844d2605d057488d77fab09705f2866b86164e0a" 8120 + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== 8121 + 8122 + "@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": 8123 + version "1.11.1" 8124 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz#204892995cefb6bd1d017d52d097193bc61ddad3" 8125 + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== 8126 + 8127 + "@unrs/resolver-binding-linux-arm64-gnu@1.11.1": 8128 + version "1.11.1" 8129 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz#023eb0c3aac46066a10be7a3f362e7b34f3bdf9d" 8130 + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== 8131 + 8132 + "@unrs/resolver-binding-linux-arm64-musl@1.11.1": 8133 + version "1.11.1" 8134 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz#9e6f9abb06424e3140a60ac996139786f5d99be0" 8135 + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== 8136 + 8137 + "@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": 8138 + version "1.11.1" 8139 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz#b111417f17c9d1b02efbec8e08398f0c5527bb44" 8140 + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== 8141 + 8142 + "@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": 8143 + version "1.11.1" 8144 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz#92ffbf02748af3e99873945c9a8a5ead01d508a9" 8145 + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== 8146 + 8147 + "@unrs/resolver-binding-linux-riscv64-musl@1.11.1": 8148 + version "1.11.1" 8149 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz#0bec6f1258fc390e6b305e9ff44256cb207de165" 8150 + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== 8151 + 8152 + "@unrs/resolver-binding-linux-s390x-gnu@1.11.1": 8153 + version "1.11.1" 8154 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz#577843a084c5952f5906770633ccfb89dac9bc94" 8155 + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== 8156 + 8157 + "@unrs/resolver-binding-linux-x64-gnu@1.11.1": 8158 + version "1.11.1" 8159 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz#36fb318eebdd690f6da32ac5e0499a76fa881935" 8160 + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== 8161 + 8162 + "@unrs/resolver-binding-linux-x64-musl@1.11.1": 8163 + version "1.11.1" 8164 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz#bfb9af75f783f98f6a22c4244214efe4df1853d6" 8165 + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== 8166 + 8167 + "@unrs/resolver-binding-wasm32-wasi@1.11.1": 8168 + version "1.11.1" 8169 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz#752c359dd875684b27429500d88226d7cc72f71d" 8170 + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== 8171 + dependencies: 8172 + "@napi-rs/wasm-runtime" "^0.2.11" 8173 + 8174 + "@unrs/resolver-binding-win32-arm64-msvc@1.11.1": 8175 + version "1.11.1" 8176 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz#ce5735e600e4c2fbb409cd051b3b7da4a399af35" 8177 + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== 8178 + 8179 + "@unrs/resolver-binding-win32-ia32-msvc@1.11.1": 8180 + version "1.11.1" 8181 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz#72fc57bc7c64ec5c3de0d64ee0d1810317bc60a6" 8182 + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== 8183 + 8184 + "@unrs/resolver-binding-win32-x64-msvc@1.11.1": 8185 + version "1.11.1" 8186 + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777" 8187 + integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== 8188 + 7911 8189 "@urql/core@^5.0.0", "@urql/core@^5.0.6": 7912 8190 version "5.0.8" 7913 8191 resolved "https://registry.yarnpkg.com/@urql/core/-/core-5.0.8.tgz#eba39eaa2bf9a0a963383e87a65cba7a9ca794bd" ··· 8136 8414 resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" 8137 8415 integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== 8138 8416 8139 - acorn@^8.1.0, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0: 8417 + acorn@^8.1.0, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.1, acorn@^8.8.2: 8140 8418 version "8.10.0" 8141 8419 resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" 8142 8420 integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== 8421 + 8422 + acorn@^8.15.0: 8423 + version "8.15.0" 8424 + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" 8425 + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== 8143 8426 8144 8427 agent-base@6: 8145 8428 version "6.0.2" ··· 8413 8696 es-shim-unscopables "^1.0.0" 8414 8697 get-intrinsic "^1.2.1" 8415 8698 8416 - array.prototype.findlastindex@^1.2.5: 8417 - version "1.2.6" 8418 - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz#cfa1065c81dcb64e34557c9b81d012f6a421c564" 8419 - integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== 8699 + array.prototype.findlast@^1.2.5: 8700 + version "1.2.5" 8701 + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" 8702 + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== 8420 8703 dependencies: 8421 - call-bind "^1.0.8" 8422 - call-bound "^1.0.4" 8704 + call-bind "^1.0.7" 8423 8705 define-properties "^1.2.1" 8424 - es-abstract "^1.23.9" 8706 + es-abstract "^1.23.2" 8425 8707 es-errors "^1.3.0" 8426 - es-object-atoms "^1.1.1" 8427 - es-shim-unscopables "^1.1.0" 8708 + es-object-atoms "^1.0.0" 8709 + es-shim-unscopables "^1.0.2" 8428 8710 8429 8711 array.prototype.flat@^1.3.1: 8430 8712 version "1.3.1" ··· 8436 8718 es-abstract "^1.20.4" 8437 8719 es-shim-unscopables "^1.0.0" 8438 8720 8439 - array.prototype.flat@^1.3.2: 8440 - version "1.3.3" 8441 - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" 8442 - integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== 8443 - dependencies: 8444 - call-bind "^1.0.8" 8445 - define-properties "^1.2.1" 8446 - es-abstract "^1.23.5" 8447 - es-shim-unscopables "^1.0.2" 8448 - 8449 8721 array.prototype.flatmap@^1.3.1: 8450 8722 version "1.3.1" 8451 8723 resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" ··· 8456 8728 es-abstract "^1.20.4" 8457 8729 es-shim-unscopables "^1.0.0" 8458 8730 8459 - array.prototype.flatmap@^1.3.2: 8731 + array.prototype.flatmap@^1.3.3: 8460 8732 version "1.3.3" 8461 8733 resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" 8462 8734 integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== ··· 8476 8748 es-abstract "^1.20.4" 8477 8749 es-shim-unscopables "^1.0.0" 8478 8750 get-intrinsic "^1.1.3" 8751 + 8752 + array.prototype.tosorted@^1.1.4: 8753 + version "1.1.4" 8754 + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" 8755 + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== 8756 + dependencies: 8757 + call-bind "^1.0.7" 8758 + define-properties "^1.2.1" 8759 + es-abstract "^1.23.3" 8760 + es-errors "^1.3.0" 8761 + es-shim-unscopables "^1.0.2" 8479 8762 8480 8763 arraybuffer.prototype.slice@^1.0.1: 8481 8764 version "1.0.1" ··· 9000 9283 dependencies: 9001 9284 fill-range "^7.0.1" 9002 9285 9286 + braces@^3.0.3: 9287 + version "3.0.3" 9288 + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 9289 + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 9290 + dependencies: 9291 + fill-range "^7.1.1" 9292 + 9003 9293 brorand@^1.1.0: 9004 9294 version "1.1.0" 9005 9295 resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" ··· 9521 9811 resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" 9522 9812 integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== 9523 9813 9814 + comment-parser@^1.4.1: 9815 + version "1.4.1" 9816 + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" 9817 + integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg== 9818 + 9524 9819 commondir@^1.0.1: 9525 9820 version "1.0.1" 9526 9821 resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" ··· 9706 10001 dependencies: 9707 10002 node-fetch "^2.6.12" 9708 10003 9709 - cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: 10004 + cross-spawn@^7.0.0, cross-spawn@^7.0.3: 9710 10005 version "7.0.3" 9711 10006 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 9712 10007 integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== ··· 9715 10010 shebang-command "^2.0.0" 9716 10011 which "^2.0.1" 9717 10012 10013 + cross-spawn@^7.0.6: 10014 + version "7.0.6" 10015 + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" 10016 + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== 10017 + dependencies: 10018 + path-key "^3.1.0" 10019 + shebang-command "^2.0.0" 10020 + which "^2.0.1" 10021 + 9718 10022 crypto-random-string@^2.0.0: 9719 10023 version "2.0.0" 9720 10024 resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" ··· 9978 10282 dependencies: 9979 10283 ms "2.1.2" 9980 10284 9981 - debug@^3.1.0, debug@^3.2.7: 10285 + debug@^3.1.0: 9982 10286 version "3.2.7" 9983 10287 resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" 9984 10288 integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== ··· 9996 10300 version "4.4.0" 9997 10301 resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" 9998 10302 integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== 10303 + dependencies: 10304 + ms "^2.1.3" 10305 + 10306 + debug@^4.4.1, debug@^4.4.3: 10307 + version "4.4.3" 10308 + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" 10309 + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== 9999 10310 dependencies: 10000 10311 ms "^2.1.3" 10001 10312 ··· 10219 10530 dependencies: 10220 10531 esutils "^2.0.2" 10221 10532 10222 - doctrine@^3.0.0: 10223 - version "3.0.0" 10224 - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 10225 - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 10226 - dependencies: 10227 - esutils "^2.0.2" 10228 - 10229 10533 dom-converter@^0.2.0: 10230 10534 version "0.2.0" 10231 10535 resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" ··· 10481 10785 dependencies: 10482 10786 stackframe "^1.3.4" 10483 10787 10788 + es-abstract@^1.17.5, es-abstract@^1.23.3, es-abstract@^1.23.6, es-abstract@^1.24.1: 10789 + version "1.24.1" 10790 + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.1.tgz#f0c131ed5ea1bb2411134a8dd94def09c46c7899" 10791 + integrity sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw== 10792 + dependencies: 10793 + array-buffer-byte-length "^1.0.2" 10794 + arraybuffer.prototype.slice "^1.0.4" 10795 + available-typed-arrays "^1.0.7" 10796 + call-bind "^1.0.8" 10797 + call-bound "^1.0.4" 10798 + data-view-buffer "^1.0.2" 10799 + data-view-byte-length "^1.0.2" 10800 + data-view-byte-offset "^1.0.1" 10801 + es-define-property "^1.0.1" 10802 + es-errors "^1.3.0" 10803 + es-object-atoms "^1.1.1" 10804 + es-set-tostringtag "^2.1.0" 10805 + es-to-primitive "^1.3.0" 10806 + function.prototype.name "^1.1.8" 10807 + get-intrinsic "^1.3.0" 10808 + get-proto "^1.0.1" 10809 + get-symbol-description "^1.1.0" 10810 + globalthis "^1.0.4" 10811 + gopd "^1.2.0" 10812 + has-property-descriptors "^1.0.2" 10813 + has-proto "^1.2.0" 10814 + has-symbols "^1.1.0" 10815 + hasown "^2.0.2" 10816 + internal-slot "^1.1.0" 10817 + is-array-buffer "^3.0.5" 10818 + is-callable "^1.2.7" 10819 + is-data-view "^1.0.2" 10820 + is-negative-zero "^2.0.3" 10821 + is-regex "^1.2.1" 10822 + is-set "^2.0.3" 10823 + is-shared-array-buffer "^1.0.4" 10824 + is-string "^1.1.1" 10825 + is-typed-array "^1.1.15" 10826 + is-weakref "^1.1.1" 10827 + math-intrinsics "^1.1.0" 10828 + object-inspect "^1.13.4" 10829 + object-keys "^1.1.1" 10830 + object.assign "^4.1.7" 10831 + own-keys "^1.0.1" 10832 + regexp.prototype.flags "^1.5.4" 10833 + safe-array-concat "^1.1.3" 10834 + safe-push-apply "^1.0.0" 10835 + safe-regex-test "^1.1.0" 10836 + set-proto "^1.0.0" 10837 + stop-iteration-iterator "^1.1.0" 10838 + string.prototype.trim "^1.2.10" 10839 + string.prototype.trimend "^1.0.9" 10840 + string.prototype.trimstart "^1.0.8" 10841 + typed-array-buffer "^1.0.3" 10842 + typed-array-byte-length "^1.0.3" 10843 + typed-array-byte-offset "^1.0.4" 10844 + typed-array-length "^1.0.7" 10845 + unbox-primitive "^1.1.0" 10846 + which-typed-array "^1.1.19" 10847 + 10484 10848 es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.3: 10485 10849 version "1.22.1" 10486 10850 resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" ··· 10658 11022 iterator.prototype "^1.1.0" 10659 11023 safe-array-concat "^1.0.0" 10660 11024 11025 + es-iterator-helpers@^1.2.1: 11026 + version "1.2.2" 11027 + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz#d979a9f686e2b0b72f88dbead7229924544720bc" 11028 + integrity sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w== 11029 + dependencies: 11030 + call-bind "^1.0.8" 11031 + call-bound "^1.0.4" 11032 + define-properties "^1.2.1" 11033 + es-abstract "^1.24.1" 11034 + es-errors "^1.3.0" 11035 + es-set-tostringtag "^2.1.0" 11036 + function-bind "^1.1.2" 11037 + get-intrinsic "^1.3.0" 11038 + globalthis "^1.0.4" 11039 + gopd "^1.2.0" 11040 + has-property-descriptors "^1.0.2" 11041 + has-proto "^1.2.0" 11042 + has-symbols "^1.1.0" 11043 + internal-slot "^1.1.0" 11044 + iterator.prototype "^1.1.5" 11045 + safe-array-concat "^1.1.3" 11046 + 10661 11047 es-module-lexer@^1.2.1: 10662 11048 version "1.3.0" 10663 11049 resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" ··· 10696 11082 dependencies: 10697 11083 has "^1.0.3" 10698 11084 10699 - es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: 11085 + es-shim-unscopables@^1.0.2: 10700 11086 version "1.1.0" 10701 11087 resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" 10702 11088 integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== ··· 10805 11191 resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" 10806 11192 integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== 10807 11193 10808 - eslint-import-resolver-node@^0.3.9: 10809 - version "0.3.9" 10810 - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" 10811 - integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== 11194 + eslint-import-context@^0.1.8, eslint-import-context@^0.1.9: 11195 + version "0.1.9" 11196 + resolved "https://registry.yarnpkg.com/eslint-import-context/-/eslint-import-context-0.1.9.tgz#967b0b2f0a90ef4b689125e088f790f0b7756dbe" 11197 + integrity sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg== 10812 11198 dependencies: 10813 - debug "^3.2.7" 10814 - is-core-module "^2.13.0" 10815 - resolve "^1.22.4" 11199 + get-tsconfig "^4.10.1" 11200 + stable-hash-x "^0.2.0" 10816 11201 10817 - eslint-module-utils@^2.12.0: 10818 - version "2.12.0" 10819 - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" 10820 - integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== 11202 + eslint-import-resolver-typescript@^4.4.4: 11203 + version "4.4.4" 11204 + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz#3e83a9c25f4a053fe20e1b07b47e04e8519a8720" 11205 + integrity sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw== 10821 11206 dependencies: 10822 - debug "^3.2.7" 11207 + debug "^4.4.1" 11208 + eslint-import-context "^0.1.8" 11209 + get-tsconfig "^4.10.1" 11210 + is-bun-module "^2.0.0" 11211 + stable-hash-x "^0.2.0" 11212 + tinyglobby "^0.2.14" 11213 + unrs-resolver "^1.7.11" 10823 11214 10824 11215 "eslint-plugin-bsky-internal@link:./eslint": 10825 11216 version "0.0.0" ··· 10833 11224 escape-string-regexp "^1.0.5" 10834 11225 ignore "^5.0.5" 10835 11226 10836 - eslint-plugin-ft-flow@^2.0.1, eslint-plugin-ft-flow@^2.0.3: 11227 + eslint-plugin-ft-flow@^2.0.1: 10837 11228 version "2.0.3" 10838 11229 resolved "https://registry.yarnpkg.com/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.3.tgz#3b3c113c41902bcbacf0e22b536debcfc3c819e8" 10839 11230 integrity sha512-Vbsd/b+LYA99jUbsL6viEUWShFaYQt2YQs3QN3f+aeszOhh2sgdcU0mjzDyD4yyBvMc8qy2uwvBBWfMzEX06tg== ··· 10841 11232 lodash "^4.17.21" 10842 11233 string-natural-compare "^3.0.1" 10843 11234 10844 - eslint-plugin-import@^2.31.0: 10845 - version "2.31.0" 10846 - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" 10847 - integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== 11235 + eslint-plugin-import-x@^4.16.1: 11236 + version "4.16.1" 11237 + resolved "https://registry.yarnpkg.com/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.1.tgz#a96ee1ad5ba6816f9a5573a9617935011a24c4df" 11238 + integrity sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ== 10848 11239 dependencies: 10849 - "@rtsao/scc" "^1.1.0" 10850 - array-includes "^3.1.8" 10851 - array.prototype.findlastindex "^1.2.5" 10852 - array.prototype.flat "^1.3.2" 10853 - array.prototype.flatmap "^1.3.2" 10854 - debug "^3.2.7" 10855 - doctrine "^2.1.0" 10856 - eslint-import-resolver-node "^0.3.9" 10857 - eslint-module-utils "^2.12.0" 10858 - hasown "^2.0.2" 10859 - is-core-module "^2.15.1" 11240 + "@typescript-eslint/types" "^8.35.0" 11241 + comment-parser "^1.4.1" 11242 + debug "^4.4.1" 11243 + eslint-import-context "^0.1.9" 10860 11244 is-glob "^4.0.3" 10861 - minimatch "^3.1.2" 10862 - object.fromentries "^2.0.8" 10863 - object.groupby "^1.0.3" 10864 - object.values "^1.2.0" 10865 - semver "^6.3.1" 10866 - string.prototype.trimend "^1.0.8" 10867 - tsconfig-paths "^3.15.0" 11245 + minimatch "^9.0.3 || ^10.0.1" 11246 + semver "^7.7.2" 11247 + stable-hash-x "^0.2.0" 11248 + unrs-resolver "^1.9.2" 10868 11249 10869 11250 eslint-plugin-jest@^27.9.0: 10870 11251 version "27.9.0" ··· 10873 11254 dependencies: 10874 11255 "@typescript-eslint/utils" "^5.10.0" 10875 11256 10876 - eslint-plugin-lingui@^0.2.0: 10877 - version "0.2.0" 10878 - resolved "https://registry.yarnpkg.com/eslint-plugin-lingui/-/eslint-plugin-lingui-0.2.0.tgz#4fd3355e964544f5d02fce0bea67187bf2f3ac3c" 10879 - integrity sha512-o63ySrDZlsujAaa3ybiFAjhkE1LHaKw5Z5GztiKHu1R+40tVOShy1XKvM+Q+vBykRXV9UrxE1oR79pUOSrsLVA== 11257 + eslint-plugin-lingui@^0.11.0: 11258 + version "0.11.0" 11259 + resolved "https://registry.yarnpkg.com/eslint-plugin-lingui/-/eslint-plugin-lingui-0.11.0.tgz#e33a4fe83698bb4cdfbfa816391fb79b68e6c026" 11260 + integrity sha512-O2Ixoapt5fa4VKZJgXhVwb6BHnzByIUDNMfZOhHWGMYk40GfGCho4MUfspLVrHAFLimgBPKXtCcJ8GC4YNZmfg== 10880 11261 dependencies: 10881 - "@typescript-eslint/utils" "^5.61.0" 11262 + "@typescript-eslint/utils" "^8.0.0" 11263 + micromatch "^4.0.0" 10882 11264 10883 11265 eslint-plugin-react-compiler@^19.1.0-rc.2: 10884 11266 version "19.1.0-rc.2" ··· 10897 11279 resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3" 10898 11280 integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg== 10899 11281 10900 - eslint-plugin-react-native-a11y@^3.3.0: 10901 - version "3.3.0" 10902 - resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-a11y/-/eslint-plugin-react-native-a11y-3.3.0.tgz#0485a8f18474bf54ec68d004b50167f75ffbf201" 10903 - integrity sha512-21bIs/0yROcMq7KtAG+OVNDWAh8M+6scII0iXcO3i9NYHe2xZ443yPs5KSUMSvQJeRLLjuKB7V5saqNjoMWDHA== 11282 + eslint-plugin-react-hooks@^7.0.1: 11283 + version "7.0.1" 11284 + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz#66e258db58ece50723ef20cc159f8aa908219169" 11285 + integrity sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA== 11286 + dependencies: 11287 + "@babel/core" "^7.24.4" 11288 + "@babel/parser" "^7.24.4" 11289 + hermes-parser "^0.25.1" 11290 + zod "^3.25.0 || ^4.0.0" 11291 + zod-validation-error "^3.5.0 || ^4.0.0" 11292 + 11293 + eslint-plugin-react-native-a11y@^3.5.1: 11294 + version "3.5.1" 11295 + resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-a11y/-/eslint-plugin-react-native-a11y-3.5.1.tgz#370339a308cace74409bfe582e9cfe627921f38a" 11296 + integrity sha512-vqnXZpAiov0lxYNfEYgwABpkiBYRrt0dbtOafPkw6QaFeA0uZ+s3w9opeEMoFmV36WFxLiCxHb9fvOJ+EUc2xQ== 10904 11297 dependencies: 10905 11298 "@babel/runtime" "^7.15.4" 10906 11299 ast-types-flow "^0.0.7" ··· 10919 11312 "@babel/traverse" "^7.7.4" 10920 11313 eslint-plugin-react-native-globals "^0.1.1" 10921 11314 10922 - eslint-plugin-react@^7.30.1, eslint-plugin-react@^7.33.2: 11315 + eslint-plugin-react-native@^5.0.0: 11316 + version "5.0.0" 11317 + resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-5.0.0.tgz#2ee990ba4967c557183b31121578547fb5c02d5d" 11318 + integrity sha512-VyWlyCC/7FC/aONibOwLkzmyKg4j9oI8fzrk9WYNs4I8/m436JuOTAFwLvEn1CVvc7La4cPfbCyspP4OYpP52Q== 11319 + dependencies: 11320 + eslint-plugin-react-native-globals "^0.1.1" 11321 + 11322 + eslint-plugin-react@^7.30.1: 10923 11323 version "7.33.2" 10924 11324 resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" 10925 11325 integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== ··· 10941 11341 semver "^6.3.1" 10942 11342 string.prototype.matchall "^4.0.8" 10943 11343 10944 - eslint-plugin-simple-import-sort@^12.0.0: 10945 - version "12.0.0" 10946 - resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.0.0.tgz#3cfa05d74509bd4dc329a956938823812194dbb6" 10947 - integrity sha512-8o0dVEdAkYap0Cn5kNeklaKcT1nUsa3LITWEuFk3nJifOoD+5JQGoyDUW2W/iPWwBsNBJpyJS9y4je/BgxLcyQ== 11344 + eslint-plugin-react@^7.37.5: 11345 + version "7.37.5" 11346 + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" 11347 + integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== 11348 + dependencies: 11349 + array-includes "^3.1.8" 11350 + array.prototype.findlast "^1.2.5" 11351 + array.prototype.flatmap "^1.3.3" 11352 + array.prototype.tosorted "^1.1.4" 11353 + doctrine "^2.1.0" 11354 + es-iterator-helpers "^1.2.1" 11355 + estraverse "^5.3.0" 11356 + hasown "^2.0.2" 11357 + jsx-ast-utils "^2.4.1 || ^3.0.0" 11358 + minimatch "^3.1.2" 11359 + object.entries "^1.1.9" 11360 + object.fromentries "^2.0.8" 11361 + object.values "^1.2.1" 11362 + prop-types "^15.8.1" 11363 + resolve "^2.0.0-next.5" 11364 + semver "^6.3.1" 11365 + string.prototype.matchall "^4.0.12" 11366 + string.prototype.repeat "^1.0.0" 11367 + 11368 + eslint-plugin-simple-import-sort@^12.1.1: 11369 + version "12.1.1" 11370 + resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz#e64bfdaf91c5b98a298619aa634a9f7aa43b709e" 11371 + integrity sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA== 10948 11372 10949 11373 eslint-scope@5.1.1, eslint-scope@^5.1.1: 10950 11374 version "5.1.1" ··· 10954 11378 esrecurse "^4.3.0" 10955 11379 estraverse "^4.1.1" 10956 11380 10957 - eslint-scope@^7.2.2: 10958 - version "7.2.2" 10959 - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" 10960 - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== 11381 + eslint-scope@^8.4.0: 11382 + version "8.4.0" 11383 + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" 11384 + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== 10961 11385 dependencies: 10962 11386 esrecurse "^4.3.0" 10963 11387 estraverse "^5.2.0" ··· 10967 11391 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" 10968 11392 integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== 10969 11393 10970 - eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: 11394 + eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: 10971 11395 version "3.4.3" 10972 11396 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" 10973 11397 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== 10974 11398 10975 - eslint@^8.19.0: 10976 - version "8.47.0" 10977 - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.47.0.tgz#c95f9b935463fb4fad7005e626c7621052e90806" 10978 - integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q== 11399 + eslint-visitor-keys@^4.2.1: 11400 + version "4.2.1" 11401 + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" 11402 + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== 11403 + 11404 + eslint@^9.39.2: 11405 + version "9.39.2" 11406 + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.2.tgz#cb60e6d16ab234c0f8369a3fe7cc87967faf4b6c" 11407 + integrity sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw== 10979 11408 dependencies: 10980 - "@eslint-community/eslint-utils" "^4.2.0" 10981 - "@eslint-community/regexpp" "^4.6.1" 10982 - "@eslint/eslintrc" "^2.1.2" 10983 - "@eslint/js" "^8.47.0" 10984 - "@humanwhocodes/config-array" "^0.11.10" 11409 + "@eslint-community/eslint-utils" "^4.8.0" 11410 + "@eslint-community/regexpp" "^4.12.1" 11411 + "@eslint/config-array" "^0.21.1" 11412 + "@eslint/config-helpers" "^0.4.2" 11413 + "@eslint/core" "^0.17.0" 11414 + "@eslint/eslintrc" "^3.3.1" 11415 + "@eslint/js" "9.39.2" 11416 + "@eslint/plugin-kit" "^0.4.1" 11417 + "@humanfs/node" "^0.16.6" 10985 11418 "@humanwhocodes/module-importer" "^1.0.1" 10986 - "@nodelib/fs.walk" "^1.2.8" 11419 + "@humanwhocodes/retry" "^0.4.2" 11420 + "@types/estree" "^1.0.6" 10987 11421 ajv "^6.12.4" 10988 11422 chalk "^4.0.0" 10989 - cross-spawn "^7.0.2" 11423 + cross-spawn "^7.0.6" 10990 11424 debug "^4.3.2" 10991 - doctrine "^3.0.0" 10992 11425 escape-string-regexp "^4.0.0" 10993 - eslint-scope "^7.2.2" 10994 - eslint-visitor-keys "^3.4.3" 10995 - espree "^9.6.1" 10996 - esquery "^1.4.2" 11426 + eslint-scope "^8.4.0" 11427 + eslint-visitor-keys "^4.2.1" 11428 + espree "^10.4.0" 11429 + esquery "^1.5.0" 10997 11430 esutils "^2.0.2" 10998 11431 fast-deep-equal "^3.1.3" 10999 - file-entry-cache "^6.0.1" 11432 + file-entry-cache "^8.0.0" 11000 11433 find-up "^5.0.0" 11001 11434 glob-parent "^6.0.2" 11002 - globals "^13.19.0" 11003 - graphemer "^1.4.0" 11004 11435 ignore "^5.2.0" 11005 11436 imurmurhash "^0.1.4" 11006 11437 is-glob "^4.0.0" 11007 - is-path-inside "^3.0.3" 11008 - js-yaml "^4.1.0" 11009 11438 json-stable-stringify-without-jsonify "^1.0.1" 11010 - levn "^0.4.1" 11011 11439 lodash.merge "^4.6.2" 11012 11440 minimatch "^3.1.2" 11013 11441 natural-compare "^1.4.0" 11014 11442 optionator "^0.9.3" 11015 - strip-ansi "^6.0.1" 11016 - text-table "^0.2.0" 11017 11443 11018 - espree@^9.6.0, espree@^9.6.1: 11019 - version "9.6.1" 11020 - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" 11021 - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== 11444 + espree@^10.0.1, espree@^10.4.0: 11445 + version "10.4.0" 11446 + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" 11447 + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== 11022 11448 dependencies: 11023 - acorn "^8.9.0" 11449 + acorn "^8.15.0" 11024 11450 acorn-jsx "^5.3.2" 11025 - eslint-visitor-keys "^3.4.1" 11451 + eslint-visitor-keys "^4.2.1" 11026 11452 11027 11453 esprima@^4.0.0, esprima@^4.0.1: 11028 11454 version "4.0.1" 11029 11455 resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 11030 11456 integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 11031 11457 11032 - esquery@^1.4.2: 11033 - version "1.5.0" 11034 - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" 11035 - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== 11458 + esquery@^1.5.0: 11459 + version "1.7.0" 11460 + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" 11461 + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== 11036 11462 dependencies: 11037 11463 estraverse "^5.1.0" 11038 11464 ··· 11718 12144 dependencies: 11719 12145 escape-string-regexp "^1.0.5" 11720 12146 11721 - file-entry-cache@^6.0.1: 11722 - version "6.0.1" 11723 - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 11724 - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 12147 + file-entry-cache@^8.0.0: 12148 + version "8.0.0" 12149 + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" 12150 + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== 11725 12151 dependencies: 11726 - flat-cache "^3.0.4" 12152 + flat-cache "^4.0.0" 11727 12153 11728 12154 file-loader@6.2.0: 11729 12155 version "6.2.0" ··· 11751 12177 version "7.0.1" 11752 12178 resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 11753 12179 integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 12180 + dependencies: 12181 + to-regex-range "^5.0.1" 12182 + 12183 + fill-range@^7.1.1: 12184 + version "7.1.1" 12185 + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 12186 + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 11754 12187 dependencies: 11755 12188 to-regex-range "^5.0.1" 11756 12189 ··· 11831 12264 dependencies: 11832 12265 micromatch "^4.0.2" 11833 12266 11834 - flat-cache@^3.0.4: 11835 - version "3.0.4" 11836 - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" 11837 - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== 12267 + flat-cache@^4.0.0: 12268 + version "4.0.1" 12269 + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" 12270 + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== 11838 12271 dependencies: 11839 - flatted "^3.1.0" 11840 - rimraf "^3.0.2" 12272 + flatted "^3.2.9" 12273 + keyv "^4.5.4" 11841 12274 11842 - flatted@^3.1.0: 11843 - version "3.2.7" 11844 - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" 11845 - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== 12275 + flatted@^3.2.9: 12276 + version "3.3.3" 12277 + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" 12278 + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== 11846 12279 11847 12280 flow-enums-runtime@^0.0.6: 11848 12281 version "0.0.6" ··· 12076 12509 es-errors "^1.3.0" 12077 12510 get-intrinsic "^1.2.6" 12078 12511 12512 + get-tsconfig@^4.10.1: 12513 + version "4.13.0" 12514 + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.13.0.tgz#fcdd991e6d22ab9a600f00e91c318707a5d9a0d7" 12515 + integrity sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ== 12516 + dependencies: 12517 + resolve-pkg-maps "^1.0.0" 12518 + 12079 12519 getenv@^1.0.0: 12080 12520 version "1.0.0" 12081 12521 resolved "https://registry.yarnpkg.com/getenv/-/getenv-1.0.0.tgz#874f2e7544fbca53c7a4738f37de8605c3fcfc31" ··· 12176 12616 resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" 12177 12617 integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== 12178 12618 12179 - globals@^13.19.0: 12180 - version "13.21.0" 12181 - resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" 12182 - integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== 12183 - dependencies: 12184 - type-fest "^0.20.2" 12619 + globals@^14.0.0: 12620 + version "14.0.0" 12621 + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" 12622 + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== 12623 + 12624 + globals@^17.0.0: 12625 + version "17.0.0" 12626 + resolved "https://registry.yarnpkg.com/globals/-/globals-17.0.0.tgz#a4196d9cfeb4d627ba165b4647b1f5853bf90a30" 12627 + integrity sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw== 12185 12628 12186 12629 globalthis@^1.0.2, globalthis@^1.0.3: 12187 12630 version "1.0.3" ··· 12666 13109 resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" 12667 13110 integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== 12668 13111 13112 + ignore@^7.0.5: 13113 + version "7.0.5" 13114 + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" 13115 + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== 13116 + 12669 13117 image-size@^1.0.2: 12670 13118 version "1.0.2" 12671 13119 resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.2.tgz#d778b6d0ab75b2737c1556dd631652eb963bc486" ··· 12901 13349 call-bound "^1.0.3" 12902 13350 has-tostringtag "^1.0.2" 12903 13351 13352 + is-bun-module@^2.0.0: 13353 + version "2.0.0" 13354 + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-2.0.0.tgz#4d7859a87c0fcac950c95e666730e745eae8bddd" 13355 + integrity sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ== 13356 + dependencies: 13357 + semver "^7.7.1" 13358 + 12904 13359 is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: 12905 13360 version "1.2.7" 12906 13361 resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" ··· 12919 13374 integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== 12920 13375 dependencies: 12921 13376 has "^1.0.3" 12922 - 12923 - is-core-module@^2.15.1, is-core-module@^2.16.0: 12924 - version "2.16.1" 12925 - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" 12926 - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== 12927 - dependencies: 12928 - hasown "^2.0.2" 12929 13377 12930 13378 is-data-view@^1.0.1, is-data-view@^1.0.2: 12931 13379 version "1.0.2" ··· 13037 13485 resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" 13038 13486 integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== 13039 13487 13488 + is-negative-zero@^2.0.3: 13489 + version "2.0.3" 13490 + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" 13491 + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== 13492 + 13040 13493 is-number-object@^1.0.4: 13041 13494 version "1.0.7" 13042 13495 resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" ··· 13076 13529 dependencies: 13077 13530 path-is-inside "^1.0.2" 13078 13531 13079 - is-path-inside@^3.0.3: 13080 - version "3.0.3" 13081 - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 13082 - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 13083 - 13084 13532 is-plain-obj@^2.1.0: 13085 13533 version "2.1.0" 13086 13534 resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" ··· 13220 13668 dependencies: 13221 13669 call-bind "^1.0.2" 13222 13670 13223 - is-weakref@^1.1.0: 13671 + is-weakref@^1.1.0, is-weakref@^1.1.1: 13224 13672 version "1.1.1" 13225 13673 resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" 13226 13674 integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== ··· 13334 13782 has-tostringtag "^1.0.0" 13335 13783 reflect.getprototypeof "^1.0.3" 13336 13784 13785 + iterator.prototype@^1.1.5: 13786 + version "1.1.5" 13787 + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39" 13788 + integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== 13789 + dependencies: 13790 + define-data-property "^1.1.4" 13791 + es-object-atoms "^1.0.0" 13792 + get-intrinsic "^1.2.6" 13793 + get-proto "^1.0.0" 13794 + has-symbols "^1.1.0" 13795 + set-function-name "^2.0.2" 13796 + 13337 13797 jackspeak@^2.3.6: 13338 13798 version "2.3.6" 13339 13799 resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" ··· 13934 14394 dependencies: 13935 14395 argparse "^2.0.1" 13936 14396 14397 + js-yaml@^4.1.1: 14398 + version "4.1.1" 14399 + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" 14400 + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== 14401 + dependencies: 14402 + argparse "^2.0.1" 14403 + 13937 14404 jsc-safe-url@^0.2.2, jsc-safe-url@^0.2.4: 13938 14405 version "0.2.4" 13939 14406 resolved "https://registry.yarnpkg.com/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz#141c14fbb43791e88d5dc64e85a374575a83477a" ··· 13986 14453 resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" 13987 14454 integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== 13988 14455 14456 + json-buffer@3.0.1: 14457 + version "3.0.1" 14458 + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" 14459 + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== 14460 + 13989 14461 json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: 13990 14462 version "2.3.1" 13991 14463 resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" ··· 14024 14496 jsonify "^0.0.1" 14025 14497 object-keys "^1.1.1" 14026 14498 14027 - json5@^1.0.2: 14028 - version "1.0.2" 14029 - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" 14030 - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== 14031 - dependencies: 14032 - minimist "^1.2.0" 14033 - 14034 14499 json5@^2.1.2, json5@^2.2.2, json5@^2.2.3: 14035 14500 version "2.2.3" 14036 14501 resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" ··· 14074 14539 asn1.js "^5.0.1" 14075 14540 bn.js "^4.11.8" 14076 14541 elliptic "^6.4.1" 14542 + 14543 + keyv@^4.5.4: 14544 + version "4.5.4" 14545 + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" 14546 + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== 14547 + dependencies: 14548 + json-buffer "3.0.1" 14077 14549 14078 14550 klaw-sync@^6.0.0: 14079 14551 version "6.0.0" ··· 14791 15263 braces "^3.0.2" 14792 15264 picomatch "^2.3.1" 14793 15265 15266 + micromatch@^4.0.0: 15267 + version "4.0.8" 15268 + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" 15269 + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== 15270 + dependencies: 15271 + braces "^3.0.3" 15272 + picomatch "^2.3.1" 15273 + 14794 15274 mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": 14795 15275 version "1.52.0" 14796 15276 resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" ··· 14850 15330 resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" 14851 15331 integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== 14852 15332 14853 - minimatch@^10.1.1: 15333 + minimatch@^10.1.1, "minimatch@^9.0.3 || ^10.0.1": 14854 15334 version "10.1.1" 14855 15335 resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.1.1.tgz#e6e61b9b0c1dcab116b5a7d1458e8b6ae9e73a55" 14856 15336 integrity sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ== 14857 15337 dependencies: 14858 15338 "@isaacs/brace-expansion" "^5.0.0" 14859 15339 14860 - minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: 15340 + minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: 14861 15341 version "3.1.2" 14862 15342 resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 14863 15343 integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== ··· 14871 15351 dependencies: 14872 15352 brace-expansion "^2.0.1" 14873 15353 14874 - minimatch@^9.0.0: 15354 + minimatch@^9.0.0, minimatch@^9.0.5: 14875 15355 version "9.0.5" 14876 15356 resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" 14877 15357 integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== ··· 15004 15484 resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" 15005 15485 integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== 15006 15486 15487 + napi-postinstall@^0.3.0: 15488 + version "0.3.4" 15489 + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.4.tgz#7af256d6588b5f8e952b9190965d6b019653bbb9" 15490 + integrity sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ== 15491 + 15007 15492 natural-compare@^1.4.0: 15008 15493 version "1.4.0" 15009 15494 resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" ··· 15181 15666 resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" 15182 15667 integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== 15183 15668 15184 - object-inspect@^1.13.3: 15669 + object-inspect@^1.13.3, object-inspect@^1.13.4: 15185 15670 version "1.13.4" 15186 15671 resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" 15187 15672 integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== ··· 15230 15715 define-properties "^1.1.4" 15231 15716 es-abstract "^1.20.4" 15232 15717 15718 + object.entries@^1.1.9: 15719 + version "1.1.9" 15720 + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.9.tgz#e4770a6a1444afb61bd39f984018b5bede25f8b3" 15721 + integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== 15722 + dependencies: 15723 + call-bind "^1.0.8" 15724 + call-bound "^1.0.4" 15725 + define-properties "^1.2.1" 15726 + es-object-atoms "^1.1.1" 15727 + 15233 15728 object.fromentries@^2.0.6: 15234 15729 version "2.0.6" 15235 15730 resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" ··· 15249 15744 es-abstract "^1.23.2" 15250 15745 es-object-atoms "^1.0.0" 15251 15746 15252 - object.groupby@^1.0.3: 15253 - version "1.0.3" 15254 - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" 15255 - integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== 15256 - dependencies: 15257 - call-bind "^1.0.7" 15258 - define-properties "^1.2.1" 15259 - es-abstract "^1.23.2" 15260 - 15261 15747 object.hasown@^1.1.2: 15262 15748 version "1.1.2" 15263 15749 resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" ··· 15275 15761 define-properties "^1.1.4" 15276 15762 es-abstract "^1.20.4" 15277 15763 15278 - object.values@^1.2.0: 15764 + object.values@^1.2.1: 15279 15765 version "1.2.1" 15280 15766 resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" 15281 15767 integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== ··· 17216 17702 define-properties "^1.2.0" 17217 17703 set-function-name "^2.0.0" 17218 17704 17219 - regexp.prototype.flags@^1.5.3: 17705 + regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: 17220 17706 version "1.5.4" 17221 17707 resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" 17222 17708 integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== ··· 17360 17846 dependencies: 17361 17847 global-dirs "^0.1.1" 17362 17848 17849 + resolve-pkg-maps@^1.0.0: 17850 + version "1.0.0" 17851 + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" 17852 + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== 17853 + 17363 17854 resolve-workspace-root@^2.0.0: 17364 17855 version "2.0.0" 17365 17856 resolved "https://registry.yarnpkg.com/resolve-workspace-root/-/resolve-workspace-root-2.0.0.tgz#a0098daa0067cd0efa6eb525c57c8fb4a61e78f8" ··· 17384 17875 path-parse "^1.0.7" 17385 17876 supports-preserve-symlinks-flag "^1.0.0" 17386 17877 17387 - resolve@^1.22.4: 17388 - version "1.22.10" 17389 - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" 17390 - integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== 17391 - dependencies: 17392 - is-core-module "^2.16.0" 17393 - path-parse "^1.0.7" 17394 - supports-preserve-symlinks-flag "^1.0.0" 17395 - 17396 17878 resolve@^1.22.8: 17397 17879 version "1.22.8" 17398 17880 resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" ··· 17408 17890 integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== 17409 17891 dependencies: 17410 17892 is-core-module "^2.9.0" 17893 + path-parse "^1.0.7" 17894 + supports-preserve-symlinks-flag "^1.0.0" 17895 + 17896 + resolve@^2.0.0-next.5: 17897 + version "2.0.0-next.5" 17898 + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" 17899 + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== 17900 + dependencies: 17901 + is-core-module "^2.13.0" 17411 17902 path-parse "^1.0.7" 17412 17903 supports-preserve-symlinks-flag "^1.0.0" 17413 17904 ··· 17684 18175 version "7.6.2" 17685 18176 resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" 17686 18177 integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== 18178 + 18179 + semver@^7.7.1, semver@^7.7.2, semver@^7.7.3: 18180 + version "7.7.3" 18181 + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" 18182 + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== 17687 18183 17688 18184 send@0.18.0: 17689 18185 version "0.18.0" ··· 18182 18678 resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 18183 18679 integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== 18184 18680 18681 + stable-hash-x@^0.2.0: 18682 + version "0.2.0" 18683 + resolved "https://registry.yarnpkg.com/stable-hash-x/-/stable-hash-x-0.2.0.tgz#dfd76bfa5d839a7470125c6a6b3c8b22061793e9" 18684 + integrity sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ== 18685 + 18185 18686 stable@^0.1.8: 18186 18687 version "0.1.8" 18187 18688 resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" ··· 18283 18784 resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 18284 18785 integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== 18285 18786 18787 + stop-iteration-iterator@^1.1.0: 18788 + version "1.1.0" 18789 + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" 18790 + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== 18791 + dependencies: 18792 + es-errors "^1.3.0" 18793 + internal-slot "^1.1.0" 18794 + 18286 18795 stream-browserify@3.0.0: 18287 18796 version "3.0.0" 18288 18797 resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" ··· 18354 18863 emoji-regex "^9.2.2" 18355 18864 strip-ansi "^7.0.1" 18356 18865 18866 + string.prototype.matchall@^4.0.12: 18867 + version "4.0.12" 18868 + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" 18869 + integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== 18870 + dependencies: 18871 + call-bind "^1.0.8" 18872 + call-bound "^1.0.3" 18873 + define-properties "^1.2.1" 18874 + es-abstract "^1.23.6" 18875 + es-errors "^1.3.0" 18876 + es-object-atoms "^1.0.0" 18877 + get-intrinsic "^1.2.6" 18878 + gopd "^1.2.0" 18879 + has-symbols "^1.1.0" 18880 + internal-slot "^1.1.0" 18881 + regexp.prototype.flags "^1.5.3" 18882 + set-function-name "^2.0.2" 18883 + side-channel "^1.1.0" 18884 + 18357 18885 string.prototype.matchall@^4.0.8: 18358 18886 version "4.0.8" 18359 18887 resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" ··· 18368 18896 regexp.prototype.flags "^1.4.3" 18369 18897 side-channel "^1.0.4" 18370 18898 18899 + string.prototype.repeat@^1.0.0: 18900 + version "1.0.0" 18901 + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" 18902 + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== 18903 + dependencies: 18904 + define-properties "^1.1.3" 18905 + es-abstract "^1.17.5" 18906 + 18371 18907 string.prototype.trim@^1.2.10: 18372 18908 version "1.2.10" 18373 18909 resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" ··· 18417 18953 define-properties "^1.2.0" 18418 18954 es-abstract "^1.22.1" 18419 18955 18420 - string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9: 18956 + string.prototype.trimend@^1.0.9: 18421 18957 version "1.0.9" 18422 18958 resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" 18423 18959 integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== ··· 18495 19031 integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== 18496 19032 dependencies: 18497 19033 ansi-regex "^6.0.1" 18498 - 18499 - strip-bom@^3.0.0: 18500 - version "3.0.0" 18501 - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 18502 - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== 18503 19034 18504 19035 strip-bom@^4.0.0: 18505 19036 version "4.0.0" ··· 18752 19283 dependencies: 18753 19284 utrie "^1.0.2" 18754 19285 18755 - text-table@^0.2.0: 18756 - version "0.2.0" 18757 - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 18758 - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== 18759 - 18760 19286 thenify-all@^1.0.0: 18761 19287 version "1.6.0" 18762 19288 resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" ··· 18800 19326 resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" 18801 19327 integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== 18802 19328 18803 - tinyglobby@^0.2.11: 19329 + tinyglobby@^0.2.11, tinyglobby@^0.2.14, tinyglobby@^0.2.15: 18804 19330 version "0.2.15" 18805 19331 resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" 18806 19332 integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== ··· 18918 19444 resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.0.tgz#709c6f2076e511a81557f3d07a0cbd566ae8195c" 18919 19445 integrity sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ== 18920 19446 19447 + ts-api-utils@^2.4.0: 19448 + version "2.4.0" 19449 + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz#2690579f96d2790253bdcf1ca35d569ad78f9ad8" 19450 + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== 19451 + 18921 19452 ts-interface-checker@^0.1.9: 18922 19453 version "0.1.13" 18923 19454 resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" ··· 18947 19478 resolved "https://registry.yarnpkg.com/ts-plugin-sort-import-suggestions/-/ts-plugin-sort-import-suggestions-1.0.4.tgz#d1ed6c235feb8c8bb8b34c625ea75b46e3e62925" 18948 19479 integrity sha512-85n5lm2OQQ+b7aRNK9omU1gmjMNXRsgeLwojm5u4OSY5sVBkAHTcgMQPEeHMNlyyfFW0uXnwgqAU0pNfhD96Bw== 18949 19480 18950 - tsconfig-paths@^3.15.0: 18951 - version "3.15.0" 18952 - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" 18953 - integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== 18954 - dependencies: 18955 - "@types/json5" "^0.0.29" 18956 - json5 "^1.0.2" 18957 - minimist "^1.2.6" 18958 - strip-bom "^3.0.0" 18959 - 18960 19481 tslib@^1.8.1, tslib@^1.9.0: 18961 19482 version "1.14.1" 18962 19483 resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" ··· 18997 19518 version "4.0.8" 18998 19519 resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 18999 19520 integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 19000 - 19001 - type-fest@^0.20.2: 19002 - version "0.20.2" 19003 - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 19004 - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 19005 19521 19006 19522 type-fest@^0.21.3: 19007 19523 version "0.21.3" ··· 19126 19642 integrity sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA== 19127 19643 optionalDependencies: 19128 19644 rxjs "^7.5.2" 19645 + 19646 + typescript-eslint@^8.53.0: 19647 + version "8.53.0" 19648 + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.53.0.tgz#c35ca6403cd381753aee325f67e10d6101d55f04" 19649 + integrity sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw== 19650 + dependencies: 19651 + "@typescript-eslint/eslint-plugin" "8.53.0" 19652 + "@typescript-eslint/parser" "8.53.0" 19653 + "@typescript-eslint/typescript-estree" "8.53.0" 19654 + "@typescript-eslint/utils" "8.53.0" 19129 19655 19130 19656 typescript@^5.9.2: 19131 19657 version "5.9.2" ··· 19286 19812 resolved "https://registry.yarnpkg.com/unraw/-/unraw-3.0.0.tgz#73443ed70d2ab09ccbac2b00525602d5991fbbe3" 19287 19813 integrity sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg== 19288 19814 19815 + unrs-resolver@^1.7.11, unrs-resolver@^1.9.2: 19816 + version "1.11.1" 19817 + resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9" 19818 + integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg== 19819 + dependencies: 19820 + napi-postinstall "^0.3.0" 19821 + optionalDependencies: 19822 + "@unrs/resolver-binding-android-arm-eabi" "1.11.1" 19823 + "@unrs/resolver-binding-android-arm64" "1.11.1" 19824 + "@unrs/resolver-binding-darwin-arm64" "1.11.1" 19825 + "@unrs/resolver-binding-darwin-x64" "1.11.1" 19826 + "@unrs/resolver-binding-freebsd-x64" "1.11.1" 19827 + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1" 19828 + "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1" 19829 + "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1" 19830 + "@unrs/resolver-binding-linux-arm64-musl" "1.11.1" 19831 + "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1" 19832 + "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1" 19833 + "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1" 19834 + "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1" 19835 + "@unrs/resolver-binding-linux-x64-gnu" "1.11.1" 19836 + "@unrs/resolver-binding-linux-x64-musl" "1.11.1" 19837 + "@unrs/resolver-binding-wasm32-wasi" "1.11.1" 19838 + "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1" 19839 + "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1" 19840 + "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" 19841 + 19289 19842 update-browserslist-db@^1.0.11: 19290 19843 version "1.0.11" 19291 19844 resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" ··· 19831 20384 gopd "^1.2.0" 19832 20385 has-tostringtag "^1.0.2" 19833 20386 20387 + which-typed-array@^1.1.19: 20388 + version "1.1.20" 20389 + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.20.tgz#3fdb7adfafe0ea69157b1509f3a1cd892bd1d122" 20390 + integrity sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg== 20391 + dependencies: 20392 + available-typed-arrays "^1.0.7" 20393 + call-bind "^1.0.8" 20394 + call-bound "^1.0.4" 20395 + for-each "^0.3.5" 20396 + get-proto "^1.0.1" 20397 + gopd "^1.2.0" 20398 + has-tostringtag "^1.0.2" 20399 + 19834 20400 which-typed-array@^1.1.9: 19835 20401 version "1.1.9" 19836 20402 resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" ··· 20097 20663 resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.3.0.tgz#2cfe81b62d044e0453d1aa3ae7c32a2f36dde9af" 20098 20664 integrity sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw== 20099 20665 20666 + "zod-validation-error@^3.5.0 || ^4.0.0": 20667 + version "4.0.2" 20668 + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918" 20669 + integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ== 20670 + 20100 20671 zod@3.23.8, zod@^3.14.2, zod@^3.20.2, zod@^3.22.4, zod@^3.23.8: 20101 20672 version "3.23.8" 20102 20673 resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" 20103 20674 integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== 20675 + 20676 + "zod@^3.25.0 || ^4.0.0": 20677 + version "4.3.5" 20678 + resolved "https://registry.yarnpkg.com/zod/-/zod-4.3.5.tgz#aeb269a6f9fc259b1212c348c7c5432aaa474d2a" 20679 + integrity sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==