@flickfyi/flkr 0.0.140 → 0.0.146
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@flickfyi/attestation/.turbo/turbo-build.log +7 -7
- package/node_modules/@flickfyi/biscuit/.turbo/turbo-build.log +7 -7
- package/node_modules/@flickfyi/core/.oxlintrc.json +2 -1
- package/node_modules/@flickfyi/core/.turbo/turbo-build.log +502 -95
- package/node_modules/@flickfyi/core/README.md +58 -4
- package/node_modules/@flickfyi/core/dist/index.cjs +1 -1
- package/node_modules/@flickfyi/core/dist/index.js +35 -24
- package/node_modules/@flickfyi/core/dist/kowalski/calculations.d.ts +17 -0
- package/node_modules/@flickfyi/core/dist/kowalski/calculator.d.ts +13 -0
- package/node_modules/@flickfyi/core/dist/kowalski/catalog.cjs +1 -0
- package/node_modules/@flickfyi/core/dist/kowalski/catalog.d.cts +962 -0
- package/node_modules/@flickfyi/core/dist/kowalski/catalog.d.ts +962 -0
- package/node_modules/@flickfyi/core/dist/kowalski/catalog.js +639 -0
- package/node_modules/@flickfyi/core/dist/kowalski/clocks.d.ts +4 -0
- package/node_modules/@flickfyi/core/dist/kowalski/date-time.d.ts +22 -0
- package/node_modules/@flickfyi/core/dist/kowalski/details.d.ts +7 -0
- package/node_modules/@flickfyi/core/dist/kowalski/everyday.d.ts +8 -0
- package/node_modules/@flickfyi/core/dist/kowalski/format.d.ts +4 -0
- package/node_modules/@flickfyi/core/dist/kowalski/frame.d.ts +161 -0
- package/node_modules/@flickfyi/core/dist/kowalski/index.cjs +21 -0
- package/node_modules/@flickfyi/core/dist/kowalski/index.d.cts +8 -0
- package/node_modules/@flickfyi/core/dist/kowalski/index.d.ts +8 -0
- package/node_modules/@flickfyi/core/dist/kowalski/index.js +7496 -0
- package/node_modules/@flickfyi/core/dist/kowalski/productivity.d.ts +5 -0
- package/node_modules/@flickfyi/core/dist/kowalski/recipe.d.ts +8 -0
- package/node_modules/@flickfyi/core/dist/kowalski/tools.d.ts +7 -0
- package/node_modules/@flickfyi/core/dist/kowalski/use-clock.d.ts +6 -0
- package/node_modules/@flickfyi/core/dist/kowalski/use-configured-feature.d.ts +19 -0
- package/node_modules/@flickfyi/core/dist/kowalski/use-feature-store.d.ts +15 -0
- package/node_modules/@flickfyi/core/dist/kowalski.css +506 -0
- package/node_modules/@flickfyi/core/dist/molecules/field/field.d.ts +8 -0
- package/node_modules/@flickfyi/core/dist/molecules/index.cjs +1 -1
- package/node_modules/@flickfyi/core/dist/molecules/index.d.cts +3 -0
- package/node_modules/@flickfyi/core/dist/molecules/index.d.ts +3 -0
- package/node_modules/@flickfyi/core/dist/molecules/index.js +88 -27
- package/node_modules/@flickfyi/core/dist/molecules/segmented/segmented.d.ts +10 -0
- package/node_modules/@flickfyi/core/dist/molecules/stepper/stepper.d.ts +10 -0
- package/node_modules/@flickfyi/core/dist/quantum/use-store.d.ts +7 -1
- package/node_modules/@flickfyi/core/dist/themes.css +2 -0
- package/node_modules/@flickfyi/core/examples/kowalski/bill-split/bill-split.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/bill-split/bill-split.tsx +17 -0
- package/node_modules/@flickfyi/core/examples/kowalski/bookmark/bookmark.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/bookmark/bookmark.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/budget/budget.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/budget/budget.tsx +26 -0
- package/node_modules/@flickfyi/core/examples/kowalski/calculator/calculator.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/calculator/calculator.tsx +24 -0
- package/node_modules/@flickfyi/core/examples/kowalski/checklist/checklist.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/checklist/checklist.tsx +26 -0
- package/node_modules/@flickfyi/core/examples/kowalski/color-palette/color-palette.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/color-palette/color-palette.tsx +22 -0
- package/node_modules/@flickfyi/core/examples/kowalski/contact/contact.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/contact/contact.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/countdown/countdown.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/countdown/countdown.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/event/event.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/event/event.tsx +24 -0
- package/node_modules/@flickfyi/core/examples/kowalski/expense/expense.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/expense/expense.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/goal/goal.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/goal/goal.tsx +24 -0
- package/node_modules/@flickfyi/core/examples/kowalski/habit/habit.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/habit/habit.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/ledger/ledger.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/ledger/ledger.tsx +25 -0
- package/node_modules/@flickfyi/core/examples/kowalski/note/note.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/note/note.tsx +22 -0
- package/node_modules/@flickfyi/core/examples/kowalski/poll/poll.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/poll/poll.tsx +26 -0
- package/node_modules/@flickfyi/core/examples/kowalski/random-picker/random-picker.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/random-picker/random-picker.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/rating/rating.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/rating/rating.tsx +19 -0
- package/node_modules/@flickfyi/core/examples/kowalski/recipe/recipe.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/recipe/recipe.tsx +120 -0
- package/node_modules/@flickfyi/core/examples/kowalski/reminder/reminder.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/reminder/reminder.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/rotation/rotation.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/rotation/rotation.tsx +27 -0
- package/node_modules/@flickfyi/core/examples/kowalski/scoreboard/scoreboard.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/scoreboard/scoreboard.tsx +26 -0
- package/node_modules/@flickfyi/core/examples/kowalski/shopping-list/shopping-list.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/shopping-list/shopping-list.tsx +27 -0
- package/node_modules/@flickfyi/core/examples/kowalski/task-board/task-board.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/task-board/task-board.tsx +27 -0
- package/node_modules/@flickfyi/core/examples/kowalski/theme.ts +3 -0
- package/node_modules/@flickfyi/core/examples/kowalski/time-zone/time-zone.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/time-zone/time-zone.tsx +22 -0
- package/node_modules/@flickfyi/core/examples/kowalski/timer/timer.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/timer/timer.tsx +23 -0
- package/node_modules/@flickfyi/core/examples/kowalski/trip/trip.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/trip/trip.tsx +26 -0
- package/node_modules/@flickfyi/core/examples/kowalski/unit-converter/unit-converter.stories.tsx +15 -0
- package/node_modules/@flickfyi/core/examples/kowalski/unit-converter/unit-converter.tsx +24 -0
- package/node_modules/@flickfyi/core/examples/parrott/calculator/calculator.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/checklist/checklist.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/countdown/countdown.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/counter/counter.stories.tsx +1 -0
- package/node_modules/@flickfyi/core/examples/parrott/fortune/fortune.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/grid/grid.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/kale-smoothie/kale-smoothie.stories.tsx +1 -0
- package/node_modules/@flickfyi/core/examples/parrott/list/list.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/log/log.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/timed-task/timed-task.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/examples/parrott/timer/timer.stories.tsx +3 -1
- package/node_modules/@flickfyi/core/fixtures/native/host/project.yml +3 -0
- package/node_modules/@flickfyi/core/fixtures/native/src/catalog-features.tsx +88 -0
- package/node_modules/@flickfyi/core/package.json +35 -5
- package/node_modules/@flickfyi/core/package.tsgo.json +19 -1
- package/node_modules/@flickfyi/core/scripts/vite-globals.d.ts +2 -0
- package/node_modules/@flickfyi/core/src/generated-types.d.ts +1 -0
- package/node_modules/@flickfyi/core/src/kowalski/README.md +9 -0
- package/node_modules/@flickfyi/core/src/kowalski/calculations.ts +106 -0
- package/node_modules/@flickfyi/core/src/kowalski/calculator.ts +243 -0
- package/node_modules/@flickfyi/core/src/kowalski/catalog.ts +787 -0
- package/node_modules/@flickfyi/core/src/kowalski/clocks.tsx +464 -0
- package/node_modules/@flickfyi/core/src/kowalski/date-time.tsx +469 -0
- package/node_modules/@flickfyi/core/src/kowalski/details.tsx +1387 -0
- package/node_modules/@flickfyi/core/src/kowalski/everyday.tsx +652 -0
- package/node_modules/@flickfyi/core/src/kowalski/format.ts +48 -0
- package/node_modules/@flickfyi/core/src/kowalski/frame.tsx +351 -0
- package/node_modules/@flickfyi/core/src/kowalski/index.ts +23 -0
- package/node_modules/@flickfyi/core/src/kowalski/productivity.tsx +575 -0
- package/node_modules/@flickfyi/core/src/kowalski/recipe.tsx +555 -0
- package/node_modules/@flickfyi/core/src/kowalski/stories/composition.stories.tsx +47 -0
- package/node_modules/@flickfyi/core/src/kowalski/stories/composition.tsx +100 -0
- package/node_modules/@flickfyi/core/src/kowalski/tools.tsx +1213 -0
- package/node_modules/@flickfyi/core/src/kowalski/use-clock.ts +19 -0
- package/node_modules/@flickfyi/core/src/kowalski/use-configured-feature.ts +85 -0
- package/node_modules/@flickfyi/core/src/kowalski/use-feature-store.ts +119 -0
- package/node_modules/@flickfyi/core/src/molecules/field/field.tsx +34 -0
- package/node_modules/@flickfyi/core/src/molecules/index.ts +3 -0
- package/node_modules/@flickfyi/core/src/molecules/segmented/segmented.tsx +48 -0
- package/node_modules/@flickfyi/core/src/molecules/stepper/stepper.tsx +54 -0
- package/node_modules/@flickfyi/core/src/quantum/use-store.ts +41 -16
- package/node_modules/@flickfyi/core/tests/fly.test.ts +34 -7
- package/node_modules/@flickfyi/core/tests/kowalski-calculations.test.ts +60 -0
- package/node_modules/@flickfyi/core/tests/kowalski-calculator.test.ts +142 -0
- package/node_modules/@flickfyi/core/tests/kowalski-contracts.test.ts +223 -0
- package/node_modules/@flickfyi/core/tests/kowalski-date-time.test.tsx +462 -0
- package/node_modules/@flickfyi/core/tests/kowalski-features.test.tsx +2158 -0
- package/node_modules/@flickfyi/core/tests/kowalski-store.test.tsx +514 -0
- package/node_modules/@flickfyi/core/tests/preview-build.test.ts +1 -1
- package/node_modules/@flickfyi/core/tests/quantum-use-store.test.ts +53 -1
- package/node_modules/@flickfyi/core/tests/verify-tsgo-assets.test.ts +1 -1
- package/node_modules/@flickfyi/core/tsconfig.vite-dts.json +2 -1
- package/node_modules/@flickfyi/core/tsgo.bun.lock +111 -9
- package/node_modules/@flickfyi/core/tsgo.package.json +21 -3
- package/node_modules/@flickfyi/core/vite.config.ts +9 -5
- package/node_modules/@flickfyi/core/vitest.config.ts +1 -1
- package/node_modules/@flickfyi/http-message-sig/.turbo/turbo-build.log +7 -7
- package/node_modules/@flickfyi/identity/.turbo/turbo-build.log +8 -9
- package/node_modules/@flickfyi/lens/.turbo/turbo-build.log +7 -7
- package/node_modules/@flickfyi/photon/.turbo/turbo-build.log +9 -9
- package/node_modules/@flickfyi/photon/Sources/Photon/Components/Button.swift +29 -2
- package/node_modules/@flickfyi/photon/Sources/PhotonVersion/Resources/photon-version.json +1 -1
- package/node_modules/@flickfyi/photon/Tests/PhotonTests/Components/ButtonHostTests.swift +26 -0
- package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-features.styles.json +1 -0
- package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-native.styles.json +1 -1
- package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-scale.styles.json +1 -1
- package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-theme.styles.json +1 -1
- package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-typography.styles.json +1 -1
- package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/stylex-calculator.styles.json +1 -1
- package/node_modules/@flickfyi/photon/dist/globals.d.ts +5 -0
- package/node_modules/@flickfyi/photon/dist/version.cjs +1 -1
- package/node_modules/@flickfyi/photon/dist/version.js +1 -1
- package/node_modules/@flickfyi/photon/generated/react-swiftui.d.ts +1 -0
- package/node_modules/@flickfyi/photon/package.json +1 -1
- package/node_modules/@flickfyi/photon/src/globals.d.ts +5 -0
- package/node_modules/@flickfyi/rwsdk-extensions/.turbo/turbo-build.log +7 -7
- package/node_modules/@formatjs/fast-memoize/LICENSE.md +9 -0
- package/node_modules/@formatjs/fast-memoize/README.md +3 -0
- package/node_modules/@formatjs/fast-memoize/index.d.ts +35 -0
- package/node_modules/@formatjs/fast-memoize/index.js +69 -0
- package/node_modules/@formatjs/fast-memoize/index.js.map +1 -0
- package/node_modules/@formatjs/fast-memoize/package.json +25 -0
- package/node_modules/@formatjs/icu-messageformat-parser/LICENSE.md +9 -0
- package/node_modules/@formatjs/icu-messageformat-parser/README.md +38 -0
- package/node_modules/@formatjs/icu-messageformat-parser/index.d.ts +393 -0
- package/node_modules/@formatjs/icu-messageformat-parser/index.js +2187 -0
- package/node_modules/@formatjs/icu-messageformat-parser/index.js.map +1 -0
- package/node_modules/@formatjs/icu-messageformat-parser/manipulator.d.ts +175 -0
- package/node_modules/@formatjs/icu-messageformat-parser/manipulator.js +209 -0
- package/node_modules/@formatjs/icu-messageformat-parser/manipulator.js.map +1 -0
- package/node_modules/@formatjs/icu-messageformat-parser/no-parser.d.ts +183 -0
- package/node_modules/@formatjs/icu-messageformat-parser/no-parser.js +162 -0
- package/node_modules/@formatjs/icu-messageformat-parser/no-parser.js.map +1 -0
- package/node_modules/@formatjs/icu-messageformat-parser/package.json +21 -0
- package/node_modules/@formatjs/icu-messageformat-parser/printer.d.ts +154 -0
- package/node_modules/@formatjs/icu-messageformat-parser/printer.js +224 -0
- package/node_modules/@formatjs/icu-messageformat-parser/printer.js.map +1 -0
- package/node_modules/@formatjs/icu-skeleton-parser/LICENSE.md +9 -0
- package/node_modules/@formatjs/icu-skeleton-parser/README.md +1 -0
- package/node_modules/@formatjs/icu-skeleton-parser/index.d.ts +67 -0
- package/node_modules/@formatjs/icu-skeleton-parser/index.js +380 -0
- package/node_modules/@formatjs/icu-skeleton-parser/index.js.map +1 -0
- package/node_modules/@formatjs/icu-skeleton-parser/package.json +15 -0
- package/node_modules/@formatjs/intl/LICENSE.md +9 -0
- package/node_modules/@formatjs/intl/README.md +3 -0
- package/node_modules/@formatjs/intl/index.d.ts +499 -0
- package/node_modules/@formatjs/intl/index.js +595 -0
- package/node_modules/@formatjs/intl/index.js.map +1 -0
- package/node_modules/@formatjs/intl/package.json +37 -0
- package/node_modules/decimal.js/LICENCE.md +23 -0
- package/node_modules/decimal.js/README.md +246 -0
- package/node_modules/decimal.js/decimal.d.ts +301 -0
- package/node_modules/decimal.js/decimal.js +4951 -0
- package/node_modules/decimal.js/decimal.mjs +4914 -0
- package/node_modules/decimal.js/package.json +55 -0
- package/node_modules/format-quantity/LICENSE +21 -0
- package/node_modules/format-quantity/README.md +181 -0
- package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.development.d.ts +131 -0
- package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.development.js +214 -0
- package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.development.js.map +1 -0
- package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.production.d.ts +131 -0
- package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.production.js +2 -0
- package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.production.js.map +1 -0
- package/node_modules/format-quantity/dist/cjs/index.d.ts +1 -0
- package/node_modules/format-quantity/dist/cjs/index.js +6 -0
- package/node_modules/format-quantity/dist/format-quantity.d.mts +131 -0
- package/node_modules/format-quantity/dist/format-quantity.legacy-esm.d.ts +131 -0
- package/node_modules/format-quantity/dist/format-quantity.legacy-esm.js +268 -0
- package/node_modules/format-quantity/dist/format-quantity.legacy-esm.js.map +1 -0
- package/node_modules/format-quantity/dist/format-quantity.mjs +208 -0
- package/node_modules/format-quantity/dist/format-quantity.mjs.map +1 -0
- package/node_modules/format-quantity/dist/format-quantity.production.d.mts +131 -0
- package/node_modules/format-quantity/dist/format-quantity.production.mjs +2 -0
- package/node_modules/format-quantity/dist/format-quantity.production.mjs.map +1 -0
- package/node_modules/format-quantity/dist/format-quantity.umd.min.js +3 -0
- package/node_modules/format-quantity/dist/format-quantity.umd.min.js.map +1 -0
- package/node_modules/format-quantity/package.json +81 -0
- package/node_modules/intl-messageformat/LICENSE.md +33 -0
- package/node_modules/intl-messageformat/README.md +3 -0
- package/node_modules/intl-messageformat/index.d.ts +177 -0
- package/node_modules/intl-messageformat/index.js +327 -0
- package/node_modules/intl-messageformat/index.js.map +1 -0
- package/node_modules/intl-messageformat/intl-messageformat.iife.js +2819 -0
- package/node_modules/intl-messageformat/package.json +40 -0
- package/node_modules/numeric-quantity/LICENSE +21 -0
- package/node_modules/numeric-quantity/README.md +306 -0
- package/node_modules/numeric-quantity/dist/cjs/index.d.ts +1 -0
- package/node_modules/numeric-quantity/dist/cjs/index.js +6 -0
- package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.development.d.ts +293 -0
- package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.development.js +579 -0
- package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.development.js.map +1 -0
- package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.production.d.ts +293 -0
- package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.production.js +2 -0
- package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.production.js.map +1 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.d.mts +293 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.iife.umd.min.js +2 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.iife.umd.min.js.map +1 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.legacy-esm.d.ts +293 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.legacy-esm.js +622 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.legacy-esm.js.map +1 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.mjs +564 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.mjs.map +1 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.production.d.mts +293 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.production.mjs +2 -0
- package/node_modules/numeric-quantity/dist/numeric-quantity.production.mjs.map +1 -0
- package/node_modules/numeric-quantity/package.json +72 -0
- package/node_modules/validator/LICENSE +20 -0
- package/node_modules/validator/README.md +269 -0
- package/node_modules/validator/es/index.js +218 -0
- package/node_modules/validator/es/lib/alpha.js +151 -0
- package/node_modules/validator/es/lib/blacklist.js +5 -0
- package/node_modules/validator/es/lib/contains.js +15 -0
- package/node_modules/validator/es/lib/equals.js +5 -0
- package/node_modules/validator/es/lib/escape.js +5 -0
- package/node_modules/validator/es/lib/isAbaRouting.js +15 -0
- package/node_modules/validator/es/lib/isAfter.js +10 -0
- package/node_modules/validator/es/lib/isAlpha.js +23 -0
- package/node_modules/validator/es/lib/isAlphanumeric.js +23 -0
- package/node_modules/validator/es/lib/isAscii.js +10 -0
- package/node_modules/validator/es/lib/isBIC.js +16 -0
- package/node_modules/validator/es/lib/isBase32.js +15 -0
- package/node_modules/validator/es/lib/isBase58.js +8 -0
- package/node_modules/validator/es/lib/isBase64.js +23 -0
- package/node_modules/validator/es/lib/isBefore.js +10 -0
- package/node_modules/validator/es/lib/isBoolean.js +15 -0
- package/node_modules/validator/es/lib/isBtcAddress.js +7 -0
- package/node_modules/validator/es/lib/isByteLength.js +19 -0
- package/node_modules/validator/es/lib/isCreditCard.js +43 -0
- package/node_modules/validator/es/lib/isCurrency.js +74 -0
- package/node_modules/validator/es/lib/isDataURI.js +31 -0
- package/node_modules/validator/es/lib/isDate.js +93 -0
- package/node_modules/validator/es/lib/isDecimal.js +22 -0
- package/node_modules/validator/es/lib/isDivisibleBy.js +6 -0
- package/node_modules/validator/es/lib/isEAN.js +70 -0
- package/node_modules/validator/es/lib/isEmail.js +165 -0
- package/node_modules/validator/es/lib/isEmpty.js +10 -0
- package/node_modules/validator/es/lib/isEthereumAddress.js +6 -0
- package/node_modules/validator/es/lib/isFQDN.js +67 -0
- package/node_modules/validator/es/lib/isFloat.js +14 -0
- package/node_modules/validator/es/lib/isFullWidth.js +6 -0
- package/node_modules/validator/es/lib/isHSL.js +13 -0
- package/node_modules/validator/es/lib/isHalfWidth.js +6 -0
- package/node_modules/validator/es/lib/isHash.js +21 -0
- package/node_modules/validator/es/lib/isHexColor.js +13 -0
- package/node_modules/validator/es/lib/isHexadecimal.js +6 -0
- package/node_modules/validator/es/lib/isIBAN.js +171 -0
- package/node_modules/validator/es/lib/isIMEI.js +40 -0
- package/node_modules/validator/es/lib/isIP.js +58 -0
- package/node_modules/validator/es/lib/isIPRange.js +41 -0
- package/node_modules/validator/es/lib/isISBN.js +47 -0
- package/node_modules/validator/es/lib/isISIN.js +55 -0
- package/node_modules/validator/es/lib/isISO15924.js +9 -0
- package/node_modules/validator/es/lib/isISO31661Alpha2.js +21 -0
- package/node_modules/validator/es/lib/isISO31661Alpha3.js +20 -0
- package/node_modules/validator/es/lib/isISO31661Numeric.js +8 -0
- package/node_modules/validator/es/lib/isISO4217.js +9 -0
- package/node_modules/validator/es/lib/isISO6346.js +28 -0
- package/node_modules/validator/es/lib/isISO6391.js +6 -0
- package/node_modules/validator/es/lib/isISO8601.js +42 -0
- package/node_modules/validator/es/lib/isISRC.js +8 -0
- package/node_modules/validator/es/lib/isISSN.js +19 -0
- package/node_modules/validator/es/lib/isIdentityCard.js +407 -0
- package/node_modules/validator/es/lib/isIn.js +23 -0
- package/node_modules/validator/es/lib/isInt.js +19 -0
- package/node_modules/validator/es/lib/isJSON.js +26 -0
- package/node_modules/validator/es/lib/isJWT.js +15 -0
- package/node_modules/validator/es/lib/isLatLong.js +21 -0
- package/node_modules/validator/es/lib/isLength.js +27 -0
- package/node_modules/validator/es/lib/isLicensePlate.js +58 -0
- package/node_modules/validator/es/lib/isLocale.js +107 -0
- package/node_modules/validator/es/lib/isLowercase.js +5 -0
- package/node_modules/validator/es/lib/isLuhnNumber.js +25 -0
- package/node_modules/validator/es/lib/isMACAddress.js +36 -0
- package/node_modules/validator/es/lib/isMD5.js +6 -0
- package/node_modules/validator/es/lib/isMagnetURI.js +9 -0
- package/node_modules/validator/es/lib/isMailtoURI.js +75 -0
- package/node_modules/validator/es/lib/isMimeType.js +40 -0
- package/node_modules/validator/es/lib/isMobilePhone.js +212 -0
- package/node_modules/validator/es/lib/isMongoId.js +6 -0
- package/node_modules/validator/es/lib/isMultibyte.js +10 -0
- package/node_modules/validator/es/lib/isNumeric.js +10 -0
- package/node_modules/validator/es/lib/isOctal.js +6 -0
- package/node_modules/validator/es/lib/isPassportNumber.js +145 -0
- package/node_modules/validator/es/lib/isPort.js +8 -0
- package/node_modules/validator/es/lib/isPostalCode.js +100 -0
- package/node_modules/validator/es/lib/isRFC3339.js +21 -0
- package/node_modules/validator/es/lib/isRgbColor.js +34 -0
- package/node_modules/validator/es/lib/isSemVer.js +14 -0
- package/node_modules/validator/es/lib/isSlug.js +6 -0
- package/node_modules/validator/es/lib/isStrongPassword.js +90 -0
- package/node_modules/validator/es/lib/isSurrogatePair.js +6 -0
- package/node_modules/validator/es/lib/isTaxID.js +1407 -0
- package/node_modules/validator/es/lib/isTime.js +22 -0
- package/node_modules/validator/es/lib/isULID.js +5 -0
- package/node_modules/validator/es/lib/isURL.js +241 -0
- package/node_modules/validator/es/lib/isUUID.js +23 -0
- package/node_modules/validator/es/lib/isUppercase.js +5 -0
- package/node_modules/validator/es/lib/isVAT.js +264 -0
- package/node_modules/validator/es/lib/isVariableWidth.js +7 -0
- package/node_modules/validator/es/lib/isWhitelisted.js +10 -0
- package/node_modules/validator/es/lib/ltrim.js +7 -0
- package/node_modules/validator/es/lib/matches.js +8 -0
- package/node_modules/validator/es/lib/normalizeEmail.js +131 -0
- package/node_modules/validator/es/lib/rtrim.js +15 -0
- package/node_modules/validator/es/lib/stripLow.js +7 -0
- package/node_modules/validator/es/lib/toBoolean.js +8 -0
- package/node_modules/validator/es/lib/toDate.js +6 -0
- package/node_modules/validator/es/lib/toFloat.js +5 -0
- package/node_modules/validator/es/lib/toInt.js +5 -0
- package/node_modules/validator/es/lib/trim.js +5 -0
- package/node_modules/validator/es/lib/unescape.js +8 -0
- package/node_modules/validator/es/lib/util/algorithms.js +79 -0
- package/node_modules/validator/es/lib/util/assertString.js +4 -0
- package/node_modules/validator/es/lib/util/checkHost.js +12 -0
- package/node_modules/validator/es/lib/util/includesArray.js +6 -0
- package/node_modules/validator/es/lib/util/includesString.js +4 -0
- package/node_modules/validator/es/lib/util/merge.js +14 -0
- package/node_modules/validator/es/lib/util/multilineRegex.js +12 -0
- package/node_modules/validator/es/lib/util/nullUndefinedCheck.js +3 -0
- package/node_modules/validator/es/lib/util/toString.js +13 -0
- package/node_modules/validator/es/lib/util/typeOf.js +10 -0
- package/node_modules/validator/es/lib/whitelist.js +5 -0
- package/node_modules/validator/index.js +229 -0
- package/node_modules/validator/lib/alpha.js +157 -0
- package/node_modules/validator/lib/blacklist.js +14 -0
- package/node_modules/validator/lib/contains.js +24 -0
- package/node_modules/validator/lib/equals.js +14 -0
- package/node_modules/validator/lib/escape.js +14 -0
- package/node_modules/validator/lib/isAbaRouting.js +23 -0
- package/node_modules/validator/lib/isAfter.js +19 -0
- package/node_modules/validator/lib/isAlpha.js +31 -0
- package/node_modules/validator/lib/isAlphanumeric.js +31 -0
- package/node_modules/validator/lib/isAscii.js +18 -0
- package/node_modules/validator/lib/isBIC.js +24 -0
- package/node_modules/validator/lib/isBase32.js +24 -0
- package/node_modules/validator/lib/isBase58.js +16 -0
- package/node_modules/validator/lib/isBase64.js +32 -0
- package/node_modules/validator/lib/isBefore.js +19 -0
- package/node_modules/validator/lib/isBoolean.js +24 -0
- package/node_modules/validator/lib/isBtcAddress.js +16 -0
- package/node_modules/validator/lib/isByteLength.js +27 -0
- package/node_modules/validator/lib/isCreditCard.js +52 -0
- package/node_modules/validator/lib/isCurrency.js +83 -0
- package/node_modules/validator/lib/isDataURI.js +40 -0
- package/node_modules/validator/lib/isDate.js +102 -0
- package/node_modules/validator/lib/isDecimal.js +31 -0
- package/node_modules/validator/lib/isDivisibleBy.js +15 -0
- package/node_modules/validator/lib/isEAN.js +78 -0
- package/node_modules/validator/lib/isEmail.js +174 -0
- package/node_modules/validator/lib/isEmpty.js +19 -0
- package/node_modules/validator/lib/isEthereumAddress.js +15 -0
- package/node_modules/validator/lib/isFQDN.js +76 -0
- package/node_modules/validator/lib/isFloat.js +22 -0
- package/node_modules/validator/lib/isFullWidth.js +14 -0
- package/node_modules/validator/lib/isHSL.js +22 -0
- package/node_modules/validator/lib/isHalfWidth.js +14 -0
- package/node_modules/validator/lib/isHash.js +30 -0
- package/node_modules/validator/lib/isHexColor.js +22 -0
- package/node_modules/validator/lib/isHexadecimal.js +15 -0
- package/node_modules/validator/lib/isIBAN.js +178 -0
- package/node_modules/validator/lib/isIMEI.js +49 -0
- package/node_modules/validator/lib/isIP.js +67 -0
- package/node_modules/validator/lib/isIPRange.js +50 -0
- package/node_modules/validator/lib/isISBN.js +56 -0
- package/node_modules/validator/lib/isISIN.js +64 -0
- package/node_modules/validator/lib/isISO15924.js +16 -0
- package/node_modules/validator/lib/isISO31661Alpha2.js +28 -0
- package/node_modules/validator/lib/isISO31661Alpha3.js +28 -0
- package/node_modules/validator/lib/isISO31661Numeric.js +16 -0
- package/node_modules/validator/lib/isISO4217.js +16 -0
- package/node_modules/validator/lib/isISO6346.js +35 -0
- package/node_modules/validator/lib/isISO6391.js +15 -0
- package/node_modules/validator/lib/isISO8601.js +50 -0
- package/node_modules/validator/lib/isISRC.js +16 -0
- package/node_modules/validator/lib/isISSN.js +28 -0
- package/node_modules/validator/lib/isIdentityCard.js +416 -0
- package/node_modules/validator/lib/isIn.js +32 -0
- package/node_modules/validator/lib/isInt.js +28 -0
- package/node_modules/validator/lib/isJSON.js +35 -0
- package/node_modules/validator/lib/isJWT.js +24 -0
- package/node_modules/validator/lib/isLatLong.js +30 -0
- package/node_modules/validator/lib/isLength.js +35 -0
- package/node_modules/validator/lib/isLicensePlate.js +67 -0
- package/node_modules/validator/lib/isLocale.js +115 -0
- package/node_modules/validator/lib/isLowercase.js +14 -0
- package/node_modules/validator/lib/isLuhnNumber.js +34 -0
- package/node_modules/validator/lib/isMACAddress.js +45 -0
- package/node_modules/validator/lib/isMD5.js +15 -0
- package/node_modules/validator/lib/isMagnetURI.js +18 -0
- package/node_modules/validator/lib/isMailtoURI.js +84 -0
- package/node_modules/validator/lib/isMimeType.js +48 -0
- package/node_modules/validator/lib/isMobilePhone.js +219 -0
- package/node_modules/validator/lib/isMongoId.js +15 -0
- package/node_modules/validator/lib/isMultibyte.js +18 -0
- package/node_modules/validator/lib/isNumeric.js +19 -0
- package/node_modules/validator/lib/isOctal.js +15 -0
- package/node_modules/validator/lib/isPassportNumber.js +152 -0
- package/node_modules/validator/lib/isPort.js +17 -0
- package/node_modules/validator/lib/isPostalCode.js +107 -0
- package/node_modules/validator/lib/isRFC3339.js +29 -0
- package/node_modules/validator/lib/isRgbColor.js +42 -0
- package/node_modules/validator/lib/isSemVer.js +22 -0
- package/node_modules/validator/lib/isSlug.js +15 -0
- package/node_modules/validator/lib/isStrongPassword.js +99 -0
- package/node_modules/validator/lib/isSurrogatePair.js +15 -0
- package/node_modules/validator/lib/isTaxID.js +1417 -0
- package/node_modules/validator/lib/isTime.js +31 -0
- package/node_modules/validator/lib/isULID.js +14 -0
- package/node_modules/validator/lib/isURL.js +249 -0
- package/node_modules/validator/lib/isUUID.js +32 -0
- package/node_modules/validator/lib/isUppercase.js +14 -0
- package/node_modules/validator/lib/isVAT.js +274 -0
- package/node_modules/validator/lib/isVariableWidth.js +16 -0
- package/node_modules/validator/lib/isWhitelisted.js +19 -0
- package/node_modules/validator/lib/ltrim.js +16 -0
- package/node_modules/validator/lib/matches.js +17 -0
- package/node_modules/validator/lib/normalizeEmail.js +140 -0
- package/node_modules/validator/lib/rtrim.js +24 -0
- package/node_modules/validator/lib/stripLow.js +16 -0
- package/node_modules/validator/lib/toBoolean.js +17 -0
- package/node_modules/validator/lib/toDate.js +15 -0
- package/node_modules/validator/lib/toFloat.js +14 -0
- package/node_modules/validator/lib/toInt.js +14 -0
- package/node_modules/validator/lib/trim.js +14 -0
- package/node_modules/validator/lib/unescape.js +17 -0
- package/node_modules/validator/lib/util/algorithms.js +88 -0
- package/node_modules/validator/lib/util/assertString.js +12 -0
- package/node_modules/validator/lib/util/checkHost.js +20 -0
- package/node_modules/validator/lib/util/includesArray.js +14 -0
- package/node_modules/validator/lib/util/includesString.js +12 -0
- package/node_modules/validator/lib/util/merge.js +22 -0
- package/node_modules/validator/lib/util/multilineRegex.js +20 -0
- package/node_modules/validator/lib/util/nullUndefinedCheck.js +11 -0
- package/node_modules/validator/lib/util/toString.js +21 -0
- package/node_modules/validator/lib/util/typeOf.js +18 -0
- package/node_modules/validator/lib/whitelist.js +14 -0
- package/node_modules/validator/package.json +76 -0
- package/node_modules/validator/validator.js +5808 -0
- package/node_modules/validator/validator.min.js +23 -0
- package/package.json +3 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useLayoutEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wall time is recomputed after suspension; interval counts are never persisted. Activation,
|
|
5
|
+
* or a change of `key`, refreshes before paint, so a clock never shows a stale time when it
|
|
6
|
+
* switches on or when what it measures (such as a timer's end) changes.
|
|
7
|
+
*/
|
|
8
|
+
export function useClock(active = true, key?: string) {
|
|
9
|
+
const [now, setNow] = useState(Date.now)
|
|
10
|
+
useLayoutEffect(() => {
|
|
11
|
+
if (!active) {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
setNow(Date.now())
|
|
15
|
+
const handle = setInterval(() => setNow(Date.now()), 1000)
|
|
16
|
+
return () => clearInterval(handle)
|
|
17
|
+
}, [active, key])
|
|
18
|
+
return now
|
|
19
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useEffect, useMemo } from 'react'
|
|
2
|
+
import type { z } from 'zod/v4'
|
|
3
|
+
|
|
4
|
+
import { useFeatureStore } from './use-feature-store'
|
|
5
|
+
|
|
6
|
+
/** Authored seeds change only at a newer manifest revision; live values otherwise win. */
|
|
7
|
+
export function useConfiguredFeature<
|
|
8
|
+
T extends { configuration: unknown; configurationRevision: number },
|
|
9
|
+
>({
|
|
10
|
+
name,
|
|
11
|
+
revision,
|
|
12
|
+
schema,
|
|
13
|
+
scope,
|
|
14
|
+
seed,
|
|
15
|
+
}: {
|
|
16
|
+
name: string
|
|
17
|
+
revision: number
|
|
18
|
+
schema: z.ZodType<T>
|
|
19
|
+
scope: 'private' | 'public'
|
|
20
|
+
seed: T
|
|
21
|
+
}) {
|
|
22
|
+
const configuration = JSON.stringify(seed)
|
|
23
|
+
const store = useFeatureStore({
|
|
24
|
+
initialState: { ...seed, configuration: seed, configurationRevision: revision },
|
|
25
|
+
name,
|
|
26
|
+
schema,
|
|
27
|
+
scope,
|
|
28
|
+
})
|
|
29
|
+
const { ready, set, value } = store
|
|
30
|
+
const current = JSON.stringify(value)
|
|
31
|
+
const attempted = useMemo<{ key?: string }>(() => ({}), [name, schema, scope])
|
|
32
|
+
const update = useMemo(() => {
|
|
33
|
+
if (!ready || revision <= value.configurationRevision) {
|
|
34
|
+
return {}
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const baseline = schema.parse(value.configuration ?? {})
|
|
38
|
+
const patch: Partial<T> = {}
|
|
39
|
+
for (const key in seed) {
|
|
40
|
+
if (
|
|
41
|
+
key !== 'configuration' &&
|
|
42
|
+
key !== 'configurationRevision' &&
|
|
43
|
+
JSON.stringify(seed[key]) !== JSON.stringify(baseline[key])
|
|
44
|
+
) {
|
|
45
|
+
patch[key] = seed[key]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const candidate = { ...patch, configuration: seed, configurationRevision: revision }
|
|
49
|
+
if (!schema.safeParse({ ...value, ...candidate }).success) {
|
|
50
|
+
return {
|
|
51
|
+
error:
|
|
52
|
+
'The requested update conflicts with your saved values. Adjust the related fields to apply it.',
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { patch: candidate }
|
|
56
|
+
} catch {
|
|
57
|
+
return {
|
|
58
|
+
error:
|
|
59
|
+
'The saved configuration could not be read. Your current values are preserved.',
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Serialized data makes equivalent renders stable, including a failed save.
|
|
63
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
64
|
+
}, [configuration, current, ready, revision, schema])
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const key = JSON.stringify([configuration, current, revision])
|
|
67
|
+
if (!update.patch || attempted.key === key) {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
attempted.key = key
|
|
71
|
+
set(update.patch)
|
|
72
|
+
}, [attempted, configuration, current, revision, set, update])
|
|
73
|
+
const retryPatch = update.patch
|
|
74
|
+
return {
|
|
75
|
+
...store,
|
|
76
|
+
error: update.error ?? store.error,
|
|
77
|
+
retry:
|
|
78
|
+
store.retry ??
|
|
79
|
+
(store.error && !store.saving && retryPatch
|
|
80
|
+
? () => {
|
|
81
|
+
set(retryPatch)
|
|
82
|
+
}
|
|
83
|
+
: undefined),
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { makeLens } from '@flickfyi/lens'
|
|
2
|
+
import { useCallback, useMemo, useSyncExternalStore } from 'react'
|
|
3
|
+
import { z } from 'zod/v4'
|
|
4
|
+
|
|
5
|
+
import { createQuantumStoreAdapter } from '~/quantum/use-store'
|
|
6
|
+
|
|
7
|
+
/** Wait for authoritative Quantum data; writes are optimistic only after hydration. */
|
|
8
|
+
export function useFeatureStore<T extends object>({
|
|
9
|
+
initialState,
|
|
10
|
+
name,
|
|
11
|
+
schema,
|
|
12
|
+
scope = 'private',
|
|
13
|
+
}: {
|
|
14
|
+
initialState: T
|
|
15
|
+
name: string
|
|
16
|
+
schema: z.ZodType<T>
|
|
17
|
+
scope?: 'private' | 'public'
|
|
18
|
+
}) {
|
|
19
|
+
const lens = useMemo(() => makeLens({ schema }), [schema])
|
|
20
|
+
const writes = useMemo<{ pending: Set<Partial<T>>; error?: string }>(
|
|
21
|
+
() => ({ pending: new Set() }),
|
|
22
|
+
[lens, name, scope]
|
|
23
|
+
)
|
|
24
|
+
const adapter = useMemo(
|
|
25
|
+
() => {
|
|
26
|
+
const adapter = createQuantumStoreAdapter<FeatureSnapshot<T>>(
|
|
27
|
+
async () =>
|
|
28
|
+
Quantum.openStore({ initialState, name, scope, version: lens.latest }),
|
|
29
|
+
{ ready: false, value: initialState },
|
|
30
|
+
async raw => {
|
|
31
|
+
const value = await lens.parse(raw.rawValue, {
|
|
32
|
+
from: z.literal(lens.latest).parse(raw.version),
|
|
33
|
+
})
|
|
34
|
+
return { ready: true, value }
|
|
35
|
+
},
|
|
36
|
+
() =>
|
|
37
|
+
adapter.replaceSnapshot({
|
|
38
|
+
...adapter.getSnapshot(),
|
|
39
|
+
loadFailed: true,
|
|
40
|
+
ready: false,
|
|
41
|
+
})
|
|
42
|
+
)
|
|
43
|
+
return adapter
|
|
44
|
+
},
|
|
45
|
+
// Initial values seed a newly created store, never replace an existing one.
|
|
46
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
47
|
+
[lens, name, scope, writes]
|
|
48
|
+
)
|
|
49
|
+
const snapshot = useSyncExternalStore(
|
|
50
|
+
adapter.subscribe,
|
|
51
|
+
adapter.getSnapshot,
|
|
52
|
+
adapter.getSnapshot
|
|
53
|
+
)
|
|
54
|
+
const set = useCallback(
|
|
55
|
+
(update: Partial<T> | ((current: T) => Partial<T>), onSaved?: () => void) => {
|
|
56
|
+
const current = adapter.getSnapshot()
|
|
57
|
+
const native = adapter.getStore()
|
|
58
|
+
const commit = native?.setAsync
|
|
59
|
+
if (!current.ready || !native || !commit || native.canWrite === false) {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
const visible = overlay(current.value, writes.pending)
|
|
63
|
+
const patch = typeof update === 'function' ? update(visible) : update
|
|
64
|
+
schema.parse({ ...visible, ...patch })
|
|
65
|
+
writes.pending.add(patch)
|
|
66
|
+
writes.error = undefined
|
|
67
|
+
adapter.replaceSnapshot({ ...current })
|
|
68
|
+
void (async () => {
|
|
69
|
+
try {
|
|
70
|
+
const raw = await commit.call(native, patch)
|
|
71
|
+
if (adapter.getStore() === native) {
|
|
72
|
+
await adapter.acceptSnapshot(raw)
|
|
73
|
+
onSaved?.()
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
writes.error = 'Could not save this change. Please try again.'
|
|
77
|
+
} finally {
|
|
78
|
+
writes.pending.delete(patch)
|
|
79
|
+
adapter.replaceSnapshot({ ...adapter.getSnapshot() })
|
|
80
|
+
}
|
|
81
|
+
})()
|
|
82
|
+
return true
|
|
83
|
+
},
|
|
84
|
+
[adapter, schema, writes]
|
|
85
|
+
)
|
|
86
|
+
const retry = useCallback(() => {
|
|
87
|
+
adapter.replaceSnapshot({ ...adapter.getSnapshot(), loadFailed: false, ready: false })
|
|
88
|
+
adapter.retry()
|
|
89
|
+
}, [adapter])
|
|
90
|
+
const supported = adapter.getStore()?.setAsync !== undefined
|
|
91
|
+
const writable = adapter.getStore()?.canWrite !== false
|
|
92
|
+
return {
|
|
93
|
+
error: snapshot.loadFailed
|
|
94
|
+
? 'Could not load this feature. Please try again.'
|
|
95
|
+
: snapshot.ready && !supported
|
|
96
|
+
? 'Update Flick to save changes to this feature.'
|
|
97
|
+
: writable
|
|
98
|
+
? writes.error
|
|
99
|
+
: 'This view is read-only.',
|
|
100
|
+
ready: snapshot.ready && supported && writable,
|
|
101
|
+
retry: snapshot.loadFailed ? retry : undefined,
|
|
102
|
+
saving: writes.pending.size > 0,
|
|
103
|
+
set,
|
|
104
|
+
value: overlay(snapshot.value, writes.pending),
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
type FeatureSnapshot<T> = {
|
|
109
|
+
loadFailed?: boolean
|
|
110
|
+
ready: boolean
|
|
111
|
+
value: T
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function overlay<T>(value: T, pending: Set<Partial<T>>) {
|
|
115
|
+
for (const patch of pending) {
|
|
116
|
+
value = { ...value, ...patch }
|
|
117
|
+
}
|
|
118
|
+
return value
|
|
119
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Flex, Text } from '@flickfyi/core'
|
|
2
|
+
import * as stylex from '@stylexjs/stylex'
|
|
3
|
+
import type { PropsWithChildren, ReactNode } from 'react'
|
|
4
|
+
|
|
5
|
+
import { space } from '~/themes/scale.stylex'
|
|
6
|
+
import { roles } from '~/themes/shared'
|
|
7
|
+
import { colors } from '~/themes/tokens.stylex'
|
|
8
|
+
|
|
9
|
+
/** One labelled control: the label above, the control, and its error below. */
|
|
10
|
+
export function Field({
|
|
11
|
+
children,
|
|
12
|
+
error,
|
|
13
|
+
label,
|
|
14
|
+
style,
|
|
15
|
+
}: PropsWithChildren<{
|
|
16
|
+
error?: ReactNode
|
|
17
|
+
label: string
|
|
18
|
+
style?: stylex.StyleXArray<stylex.StyleXStyles>
|
|
19
|
+
}>) {
|
|
20
|
+
return (
|
|
21
|
+
<Flex {...stylex.props(styles.root, style)}>
|
|
22
|
+
<Text {...stylex.props(roles.label, styles.label)}>{label}</Text>
|
|
23
|
+
{children}
|
|
24
|
+
{error && <Text {...stylex.props(roles.muted, styles.error)}>{error}</Text>}
|
|
25
|
+
</Flex>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The label reads like a Card header label: muted, in the theme's label case.
|
|
30
|
+
const styles = stylex.create({
|
|
31
|
+
error: { color: colors.danger },
|
|
32
|
+
label: { color: colors.muted },
|
|
33
|
+
root: { alignItems: 'stretch', gap: space[2], minWidth: 0 },
|
|
34
|
+
})
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { Card } from './card/card'
|
|
2
2
|
export { Choice, completedTaskStyle } from './choice/choice'
|
|
3
|
+
export { Field } from './field/field'
|
|
3
4
|
export { List } from './list/list'
|
|
4
5
|
export { Progress } from './progress/progress'
|
|
5
6
|
export { QuantityGroup } from './quantity-group/quantity-group'
|
|
7
|
+
export { Segmented } from './segmented/segmented'
|
|
6
8
|
export { Stat } from './stat/stat'
|
|
9
|
+
export { Stepper } from './stepper/stepper'
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Flex, Text } from '@flickfyi/core'
|
|
2
|
+
import * as stylex from '@stylexjs/stylex'
|
|
3
|
+
|
|
4
|
+
import { Button } from '~/atoms/button/button'
|
|
5
|
+
import { space } from '~/themes/scale.stylex'
|
|
6
|
+
import { button } from '~/themes/shared'
|
|
7
|
+
|
|
8
|
+
/** Pick one of a few options; the chosen one wears the theme's selected paint. */
|
|
9
|
+
export function Segmented<Value extends number | string>({
|
|
10
|
+
disabled = false,
|
|
11
|
+
onChange,
|
|
12
|
+
options,
|
|
13
|
+
value,
|
|
14
|
+
}: {
|
|
15
|
+
disabled?: boolean
|
|
16
|
+
onChange: (value: Value) => void
|
|
17
|
+
options: ReadonlyArray<{ label: string; value: Value }>
|
|
18
|
+
value: Value | undefined
|
|
19
|
+
}) {
|
|
20
|
+
return (
|
|
21
|
+
<Flex {...stylex.props(styles.root)}>
|
|
22
|
+
{options.map(option => (
|
|
23
|
+
<Button
|
|
24
|
+
disabled={disabled}
|
|
25
|
+
key={String(option.value)}
|
|
26
|
+
onClick={() => onChange(option.value)}
|
|
27
|
+
selected={option.value === value}
|
|
28
|
+
style={[button.secondary, styles.segment]}
|
|
29
|
+
>
|
|
30
|
+
<Text>{option.label}</Text>
|
|
31
|
+
</Button>
|
|
32
|
+
))}
|
|
33
|
+
</Flex>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Equal segments with gap-2. A segment never shrinks below its label, so a row
|
|
38
|
+
// that runs out of room wraps whole segments instead of breaking words.
|
|
39
|
+
const styles = stylex.create({
|
|
40
|
+
root: { flexDirection: 'row', flexWrap: 'wrap', gap: space[2], minWidth: 0 },
|
|
41
|
+
segment: {
|
|
42
|
+
flexBasis: 'auto',
|
|
43
|
+
flexGrow: 1,
|
|
44
|
+
flexShrink: 0,
|
|
45
|
+
paddingLeft: space[3],
|
|
46
|
+
paddingRight: space[3],
|
|
47
|
+
},
|
|
48
|
+
})
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Flex, Icon } from '@flickfyi/core'
|
|
2
|
+
import * as stylex from '@stylexjs/stylex'
|
|
3
|
+
import type { PropsWithChildren } from 'react'
|
|
4
|
+
|
|
5
|
+
import { Button } from '~/atoms/button/button'
|
|
6
|
+
import { space } from '~/themes/scale.stylex'
|
|
7
|
+
import { button } from '~/themes/shared'
|
|
8
|
+
|
|
9
|
+
/** A value between square − and + controls; the value is any text or input. */
|
|
10
|
+
export function Stepper({
|
|
11
|
+
children,
|
|
12
|
+
decrementDisabled = false,
|
|
13
|
+
decrementLabel,
|
|
14
|
+
incrementDisabled = false,
|
|
15
|
+
incrementLabel,
|
|
16
|
+
onDecrement,
|
|
17
|
+
onIncrement,
|
|
18
|
+
}: PropsWithChildren<{
|
|
19
|
+
decrementDisabled?: boolean
|
|
20
|
+
decrementLabel: string
|
|
21
|
+
incrementDisabled?: boolean
|
|
22
|
+
incrementLabel: string
|
|
23
|
+
onDecrement: () => void
|
|
24
|
+
onIncrement: () => void
|
|
25
|
+
}>) {
|
|
26
|
+
return (
|
|
27
|
+
<Flex {...stylex.props(styles.root)}>
|
|
28
|
+
<Button
|
|
29
|
+
accessibilityLabel={decrementLabel}
|
|
30
|
+
disabled={decrementDisabled}
|
|
31
|
+
onClick={onDecrement}
|
|
32
|
+
style={[button.secondary, styles.control]}
|
|
33
|
+
>
|
|
34
|
+
<Icon name="minus" />
|
|
35
|
+
</Button>
|
|
36
|
+
<Flex {...stylex.props(styles.value)}>{children}</Flex>
|
|
37
|
+
<Button
|
|
38
|
+
accessibilityLabel={incrementLabel}
|
|
39
|
+
disabled={incrementDisabled}
|
|
40
|
+
onClick={onIncrement}
|
|
41
|
+
style={[button.secondary, styles.control]}
|
|
42
|
+
>
|
|
43
|
+
<Icon name="plus" />
|
|
44
|
+
</Button>
|
|
45
|
+
</Flex>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Square size-9 controls (the Button minimum on both axes) around a growing value.
|
|
50
|
+
const styles = stylex.create({
|
|
51
|
+
control: { flexShrink: 0, paddingLeft: 0, paddingRight: 0 },
|
|
52
|
+
root: { alignItems: 'center', columnGap: space[2], flexDirection: 'row', minWidth: 0 },
|
|
53
|
+
value: { flexBasis: 0, flexGrow: 1, minWidth: 0 },
|
|
54
|
+
})
|
|
@@ -2,7 +2,9 @@ import type { AnyLens, InferLens } from '@flickfyi/lens'
|
|
|
2
2
|
import { useCallback, useMemo, useSyncExternalStore } from 'react'
|
|
3
3
|
|
|
4
4
|
type QuantumStore = {
|
|
5
|
+
canWrite?: boolean
|
|
5
6
|
set: (value: unknown) => void
|
|
7
|
+
setAsync?: (value: unknown) => Promise<QuantumStorePayload>
|
|
6
8
|
subscribe: (
|
|
7
9
|
callback: (raw: { rawValue: unknown; version: number }) => void
|
|
8
10
|
) => () => void
|
|
@@ -35,7 +37,8 @@ type UseStoreOptions<TLens extends AnyLens> = {
|
|
|
35
37
|
export function createQuantumStoreAdapter<T>(
|
|
36
38
|
openStore: () => Promise<QuantumStore>,
|
|
37
39
|
initialState: T,
|
|
38
|
-
parseSnapshot: (raw: QuantumStorePayload) => Promise<T
|
|
40
|
+
parseSnapshot: (raw: QuantumStorePayload) => Promise<T>,
|
|
41
|
+
onLoadError?: () => void
|
|
39
42
|
) {
|
|
40
43
|
let payloadGeneration = 0
|
|
41
44
|
let snapshot: T = initialState
|
|
@@ -45,6 +48,27 @@ export function createQuantumStoreAdapter<T>(
|
|
|
45
48
|
let storeUnsubscribe: (() => void) | undefined = undefined
|
|
46
49
|
const listeners = new Set<() => void>()
|
|
47
50
|
|
|
51
|
+
const acceptSnapshot = async (raw: QuantumStorePayload) => {
|
|
52
|
+
const generation = storeGeneration
|
|
53
|
+
const payload = ++payloadGeneration
|
|
54
|
+
let next: T
|
|
55
|
+
try {
|
|
56
|
+
next = await parseSnapshot(raw)
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (generation === storeGeneration && payload === payloadGeneration) {
|
|
59
|
+
onLoadError?.()
|
|
60
|
+
}
|
|
61
|
+
throw error
|
|
62
|
+
}
|
|
63
|
+
if (generation !== storeGeneration || payload !== payloadGeneration) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
snapshot = next
|
|
67
|
+
for (const listener of listeners) {
|
|
68
|
+
listener()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
48
72
|
const ensureStore = () => {
|
|
49
73
|
if (quantumStore || storePromise) {
|
|
50
74
|
return
|
|
@@ -62,21 +86,7 @@ export function createQuantumStoreAdapter<T>(
|
|
|
62
86
|
return
|
|
63
87
|
}
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
const payload = payloadGeneration
|
|
67
|
-
void parseSnapshot(raw)
|
|
68
|
-
.then(next => {
|
|
69
|
-
if (generation !== storeGeneration || payload !== payloadGeneration) {
|
|
70
|
-
return undefined
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
snapshot = next
|
|
74
|
-
for (const listener of listeners) {
|
|
75
|
-
listener()
|
|
76
|
-
}
|
|
77
|
-
return undefined
|
|
78
|
-
})
|
|
79
|
-
.catch(() => undefined)
|
|
89
|
+
void acceptSnapshot(raw).catch(() => undefined)
|
|
80
90
|
})
|
|
81
91
|
quantumStore = store
|
|
82
92
|
storeUnsubscribe = unsubscribe
|
|
@@ -90,6 +100,7 @@ export function createQuantumStoreAdapter<T>(
|
|
|
90
100
|
quantumStore = undefined
|
|
91
101
|
storePromise = undefined
|
|
92
102
|
storeUnsubscribe = undefined
|
|
103
|
+
onLoadError?.()
|
|
93
104
|
return undefined
|
|
94
105
|
})
|
|
95
106
|
}
|
|
@@ -104,8 +115,22 @@ export function createQuantumStoreAdapter<T>(
|
|
|
104
115
|
}
|
|
105
116
|
|
|
106
117
|
return {
|
|
118
|
+
acceptSnapshot,
|
|
107
119
|
getSnapshot: () => snapshot,
|
|
108
120
|
getStore: () => quantumStore,
|
|
121
|
+
/** Notify listeners after a local optimistic change or write-state update. */
|
|
122
|
+
replaceSnapshot(next: T) {
|
|
123
|
+
snapshot = next
|
|
124
|
+
for (const listener of listeners) {
|
|
125
|
+
listener()
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
retry() {
|
|
129
|
+
resetStore()
|
|
130
|
+
if (listeners.size > 0) {
|
|
131
|
+
ensureStore()
|
|
132
|
+
}
|
|
133
|
+
},
|
|
109
134
|
subscribe(onStoreChange: () => void) {
|
|
110
135
|
listeners.add(onStoreChange)
|
|
111
136
|
ensureStore()
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type SharedRuntimeStore,
|
|
12
12
|
} from 'fly-tsgo'
|
|
13
13
|
import { createRequire } from 'module'
|
|
14
|
-
import { readFileSync } from 'fs'
|
|
14
|
+
import { globSync, readFileSync } from 'fs'
|
|
15
15
|
import themes from '@flickfyi/core/themes'
|
|
16
16
|
|
|
17
17
|
const require = createRequire(import.meta.url)
|
|
@@ -137,10 +137,10 @@ describe.skipIf(shouldSkipRemoteTests)('Fly TSGo Server Tests', () => {
|
|
|
137
137
|
const first = await compileWithSharedRuntime(client, hello, { store })
|
|
138
138
|
if (!first.success) throw new Error(JSON.stringify(first.errors))
|
|
139
139
|
expect(Buffer.byteLength(first.code)).toBeLessThan(10_000)
|
|
140
|
-
expect(builds).toBe(
|
|
140
|
+
expect(builds).toBe(4)
|
|
141
141
|
const warm = await compileWithSharedRuntime(client, hello, { store })
|
|
142
142
|
expect(warm).toEqual(first)
|
|
143
|
-
expect(builds).toBe(
|
|
143
|
+
expect(builds).toBe(4)
|
|
144
144
|
const themeNames = Object.keys(themes)
|
|
145
145
|
const selectedThemes = await compileWithSharedRuntime(client, buildFileMap(`
|
|
146
146
|
import { Text, useTheme } from '@flickfyi/core'
|
|
@@ -155,7 +155,7 @@ export default function App() {
|
|
|
155
155
|
for (const name of themeNames) {
|
|
156
156
|
expect(selectedThemes.code).toContain(`@flickfyi/core/themes/${name}`)
|
|
157
157
|
}
|
|
158
|
-
expect(builds).toBe(
|
|
158
|
+
expect(builds).toBe(4)
|
|
159
159
|
const lens = await compileWithSharedRuntime(client, buildFileMap(`
|
|
160
160
|
import { makeLens } from '@flickfyi/lens';
|
|
161
161
|
import { z } from 'zod/v4';
|
|
@@ -163,12 +163,12 @@ export default function App() {
|
|
|
163
163
|
`), { store })
|
|
164
164
|
if (!lens.success) throw new Error(JSON.stringify(lens.errors))
|
|
165
165
|
expect(lens.code).not.toContain('// @flick/runtime ')
|
|
166
|
-
expect(RuntimeManifestSchema.parse(lens.runtime).libraries).toHaveLength(
|
|
167
|
-
expect(builds).toBe(
|
|
166
|
+
expect(RuntimeManifestSchema.parse(lens.runtime).libraries).toHaveLength(4)
|
|
167
|
+
expect(builds).toBe(4)
|
|
168
168
|
expect(Buffer.byteLength(lens.code)).toBeLessThan(10_000)
|
|
169
169
|
const invalid = await compileWithSharedRuntime(client, buildFileMap('export const value: number = "bad"'), { store })
|
|
170
170
|
expect(invalid.success).toBe(false)
|
|
171
|
-
expect(builds).toBe(
|
|
171
|
+
expect(builds).toBe(4)
|
|
172
172
|
})
|
|
173
173
|
|
|
174
174
|
it('compiles public Core atoms and molecules with inherited theme styles', async () => {
|
|
@@ -662,3 +662,30 @@ describe.skipIf(shouldSkipRemoteTests)('Sample App Compilation Tests', () => {
|
|
|
662
662
|
},
|
|
663
663
|
)
|
|
664
664
|
})
|
|
665
|
+
|
|
666
|
+
describe.skipIf(shouldSkipRemoteTests)('Canonical Persistent Feature Compilation Tests', () => {
|
|
667
|
+
const client = createClient()
|
|
668
|
+
const cached = new Map<string, RuntimeLibrary>()
|
|
669
|
+
const store: SharedRuntimeStore = {
|
|
670
|
+
async ensure(id, build) {
|
|
671
|
+
const existing = cached.get(id)
|
|
672
|
+
if (existing) return existing
|
|
673
|
+
const artifact = await build()
|
|
674
|
+
cached.set(id, artifact.library)
|
|
675
|
+
return artifact.library
|
|
676
|
+
},
|
|
677
|
+
}
|
|
678
|
+
const packageRoot = path.resolve(import.meta.dirname, '..')
|
|
679
|
+
const examples = globSync('examples/kowalski/*/*.tsx', {
|
|
680
|
+
cwd: packageRoot,
|
|
681
|
+
exclude: ['**/*.stories.tsx'],
|
|
682
|
+
}).sort()
|
|
683
|
+
|
|
684
|
+
it.each(examples)('compiles %s against the pinned shared runtime', async entry => {
|
|
685
|
+
const files = buildFileMap(readFileSync(path.resolve(packageRoot, entry), 'utf8'))
|
|
686
|
+
const result = await compileWithSharedRuntime(client, files, { store })
|
|
687
|
+
if (!result.success) throw new Error(`${entry}: ${JSON.stringify(result.errors)}`)
|
|
688
|
+
expect(result.code).toContain('@flickfyi/core/kowalski')
|
|
689
|
+
expect(RuntimeManifestSchema.parse(result.runtime).libraries).toHaveLength(4)
|
|
690
|
+
}, 60_000)
|
|
691
|
+
})
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
billShares,
|
|
5
|
+
convertUnit,
|
|
6
|
+
elapsedSeconds,
|
|
7
|
+
localDate,
|
|
8
|
+
nextReminder,
|
|
9
|
+
pickResult,
|
|
10
|
+
} from '~/kowalski/calculations'
|
|
11
|
+
|
|
12
|
+
describe('Kowalski calculations', () => {
|
|
13
|
+
it('restores elapsed time from an anchor, handles clock reversal, and pauses without drift', () => {
|
|
14
|
+
expect(elapsedSeconds({ elapsedSeconds: 12, startedAt: 1000 }, 11_000)).toBe(22)
|
|
15
|
+
expect(elapsedSeconds({ elapsedSeconds: 12, startedAt: 1000 }, 0)).toBe(12)
|
|
16
|
+
expect(elapsedSeconds({ elapsedSeconds: 12, startedAt: null }, 11_000)).toBe(12)
|
|
17
|
+
})
|
|
18
|
+
it('keeps per-person currency shares exact without dropping a minor unit', () => {
|
|
19
|
+
expect(billShares(10, 3, 0, 'USD')).toEqual({
|
|
20
|
+
perPerson: 3.33,
|
|
21
|
+
remainder: 0.01,
|
|
22
|
+
total: 10,
|
|
23
|
+
})
|
|
24
|
+
expect(billShares(100, 3, 0, 'JPY')).toEqual({
|
|
25
|
+
perPerson: 33,
|
|
26
|
+
remainder: 1,
|
|
27
|
+
total: 100,
|
|
28
|
+
})
|
|
29
|
+
expect(billShares(10, 2, 20, 'USD').perPerson).toBe(6)
|
|
30
|
+
expect(billShares(17.15, 1, 10, 'USD').total).toBe(18.87)
|
|
31
|
+
expect(billShares(2.75, 1, 18, 'USD').total).toBe(3.25)
|
|
32
|
+
})
|
|
33
|
+
it('converts length, mass, and temperature with their offsets', () => {
|
|
34
|
+
expect(convertUnit(1, 'mi', 'km')).toBeCloseTo(1.609344)
|
|
35
|
+
expect(convertUnit(32, 'f', 'c')).toBe(0)
|
|
36
|
+
expect(convertUnit(273.15, 'k', 'c')).toBe(0)
|
|
37
|
+
expect(convertUnit(0.1, 'm', 'km')).toBe(0.0001)
|
|
38
|
+
expect(convertUnit(0, 'c', 'k')).toBeCloseTo(273.15)
|
|
39
|
+
expect(convertUnit(0.0000001, 'k', 'k')).toBe(0.0000001)
|
|
40
|
+
expect(() => convertUnit(1, 'kg', 'km')).toThrow()
|
|
41
|
+
})
|
|
42
|
+
it('uses the selected calendar date across UTC midnight', () => {
|
|
43
|
+
expect(localDate(Date.parse('2026-10-15T01:00:00Z'), 'America/Los_Angeles')).toBe(
|
|
44
|
+
'2026-10-14'
|
|
45
|
+
)
|
|
46
|
+
expect(localDate(Date.parse('2026-10-15T01:00:00Z'), 'Asia/Tokyo')).toBe('2026-10-15')
|
|
47
|
+
})
|
|
48
|
+
it('advances a stale repeating reminder to the next future occurrence', () => {
|
|
49
|
+
expect(
|
|
50
|
+
nextReminder('2026-10-10T09:00:00Z', 'daily', Date.parse('2026-10-15T10:00:00Z'))
|
|
51
|
+
).toBe('2026-10-16T09:00:00.000Z')
|
|
52
|
+
expect(nextReminder(null, 'daily', 0)).toBeNull()
|
|
53
|
+
})
|
|
54
|
+
it('samples both ends of an inclusive range and rejects invalid randomness', () => {
|
|
55
|
+
const domain = { maximum: 2, minimum: -2, mode: 'range' as const }
|
|
56
|
+
expect(pickResult(domain, 0)).toBe(-2)
|
|
57
|
+
expect(pickResult(domain, 0.99999)).toBe(2)
|
|
58
|
+
expect(() => pickResult(domain, 1)).toThrow()
|
|
59
|
+
})
|
|
60
|
+
})
|